From bbbf71a3d6bffdf0de106591095cc82db0f49542 Mon Sep 17 00:00:00 2001 From: Jan Lentfer Date: Fri, 27 Nov 2009 09:58:23 +0100 Subject: [PATCH] Import bind 9.5.2 vendor sources. --- contrib/bind-9.5.2/CHANGES | 8182 ++++++++++++++++ contrib/bind-9.5.2/COPYRIGHT | 30 + contrib/bind-9.5.2/FAQ | 877 ++ contrib/bind-9.5.2/README | 577 ++ contrib/bind-9.5.2/README.DELETED | 175 + contrib/bind-9.5.2/README.DRAGONFLY | 58 + contrib/bind-9.5.2/README.idnkit | 112 + contrib/bind-9.5.2/bin/check/check-tool.c | 660 ++ contrib/bind-9.5.2/bin/check/check-tool.h | 55 + .../bind-9.5.2/bin/check/named-checkconf.8 | 94 + .../bind-9.5.2/bin/check/named-checkconf.c | 498 + .../bind-9.5.2/bin/check/named-checkconf.html | 96 + .../bind-9.5.2/bin/check/named-checkzone.8 | 278 + .../bind-9.5.2/bin/check/named-checkzone.c | 455 + .../bind-9.5.2/bin/check/named-checkzone.html | 262 + contrib/bind-9.5.2/bin/dig/dig.1 | 568 ++ contrib/bind-9.5.2/bin/dig/dig.c | 1839 ++++ contrib/bind-9.5.2/bin/dig/dig.html | 639 ++ contrib/bind-9.5.2/bin/dig/dighost.c | 5522 +++++++++++ contrib/bind-9.5.2/bin/dig/host.1 | 219 + contrib/bind-9.5.2/bin/dig/host.c | 878 ++ contrib/bind-9.5.2/bin/dig/host.html | 212 + contrib/bind-9.5.2/bin/dig/include/dig/dig.h | 406 + contrib/bind-9.5.2/bin/dig/nslookup.1 | 252 + contrib/bind-9.5.2/bin/dig/nslookup.c | 912 ++ contrib/bind-9.5.2/bin/dig/nslookup.html | 307 + contrib/bind-9.5.2/bin/dnssec/dnssec-keygen.8 | 200 + contrib/bind-9.5.2/bin/dnssec/dnssec-keygen.c | 535 ++ .../bind-9.5.2/bin/dnssec/dnssec-keygen.html | 232 + .../bind-9.5.2/bin/dnssec/dnssec-signzone.8 | 272 + .../bind-9.5.2/bin/dnssec/dnssec-signzone.c | 2357 +++++ .../bin/dnssec/dnssec-signzone.html | 285 + contrib/bind-9.5.2/bin/dnssec/dnssectool.c | 313 + contrib/bind-9.5.2/bin/dnssec/dnssectool.h | 76 + contrib/bind-9.5.2/bin/named/bind9.xsl | 492 + contrib/bind-9.5.2/bin/named/bind9.xsl.h | 497 + contrib/bind-9.5.2/bin/named/builtin.c | 307 + contrib/bind-9.5.2/bin/named/client.c | 2779 ++++++ contrib/bind-9.5.2/bin/named/config.c | 803 ++ contrib/bind-9.5.2/bin/named/control.c | 199 + contrib/bind-9.5.2/bin/named/controlconf.c | 1459 +++ contrib/bind-9.5.2/bin/named/convertxsl.pl | 57 + .../bin/named/include/named/builtin.h | 31 + .../bin/named/include/named/client.h | 368 + .../bin/named/include/named/config.h | 79 + .../bin/named/include/named/control.h | 95 + .../bin/named/include/named/globals.h | 123 + .../bin/named/include/named/interfacemgr.h | 176 + .../bin/named/include/named/listenlist.h | 105 + .../bind-9.5.2/bin/named/include/named/log.h | 99 + .../bin/named/include/named/logconf.h | 34 + .../bin/named/include/named/lwaddr.h | 36 + .../bin/named/include/named/lwdclient.h | 234 + .../bin/named/include/named/lwresd.h | 121 + .../bin/named/include/named/lwsearch.h | 112 + .../bind-9.5.2/bin/named/include/named/main.h | 34 + .../bin/named/include/named/notify.h | 55 + .../bin/named/include/named/ns_smf_globals.h | 44 + .../bin/named/include/named/query.h | 87 + .../bin/named/include/named/server.h | 300 + .../bin/named/include/named/sortlist.h | 87 + .../bin/named/include/named/statschannel.h | 61 + .../bin/named/include/named/tkeyconf.h | 53 + .../bin/named/include/named/tsigconf.h | 49 + .../bin/named/include/named/types.h | 46 + .../bin/named/include/named/update.h | 50 + .../bin/named/include/named/xfrout.h | 39 + .../bin/named/include/named/zoneconf.h | 63 + contrib/bind-9.5.2/bin/named/interfacemgr.c | 974 ++ contrib/bind-9.5.2/bin/named/listenlist.c | 138 + contrib/bind-9.5.2/bin/named/log.c | 236 + contrib/bind-9.5.2/bin/named/logconf.c | 299 + contrib/bind-9.5.2/bin/named/lwaddr.c | 94 + contrib/bind-9.5.2/bin/named/lwdclient.c | 468 + contrib/bind-9.5.2/bin/named/lwderror.c | 80 + contrib/bind-9.5.2/bin/named/lwdgabn.c | 657 ++ contrib/bind-9.5.2/bin/named/lwdgnba.c | 270 + contrib/bind-9.5.2/bin/named/lwdgrbn.c | 513 + contrib/bind-9.5.2/bin/named/lwdnoop.c | 87 + contrib/bind-9.5.2/bin/named/lwresd.8 | 223 + contrib/bind-9.5.2/bin/named/lwresd.c | 870 ++ contrib/bind-9.5.2/bin/named/lwresd.html | 225 + contrib/bind-9.5.2/bin/named/lwsearch.c | 206 + contrib/bind-9.5.2/bin/named/main.c | 973 ++ contrib/bind-9.5.2/bin/named/named.8 | 251 + contrib/bind-9.5.2/bin/named/named.conf.5 | 540 ++ contrib/bind-9.5.2/bin/named/named.conf.html | 574 ++ contrib/bind-9.5.2/bin/named/named.html | 280 + contrib/bind-9.5.2/bin/named/notify.c | 174 + contrib/bind-9.5.2/bin/named/query.c | 4742 +++++++++ contrib/bind-9.5.2/bin/named/server.c | 5522 +++++++++++ contrib/bind-9.5.2/bin/named/sortlist.c | 170 + contrib/bind-9.5.2/bin/named/statschannel.c | 1355 +++ contrib/bind-9.5.2/bin/named/tkeyconf.c | 128 + contrib/bind-9.5.2/bin/named/tsigconf.c | 181 + .../bin/named/unix/include/named/os.h | 71 + contrib/bind-9.5.2/bin/named/unix/os.c | 802 ++ contrib/bind-9.5.2/bin/named/update.c | 3258 +++++++ contrib/bind-9.5.2/bin/named/xfrout.c | 1843 ++++ contrib/bind-9.5.2/bin/named/zoneconf.c | 966 ++ contrib/bind-9.5.2/bin/nsupdate/nsupdate.1 | 358 + contrib/bind-9.5.2/bin/nsupdate/nsupdate.c | 2682 ++++++ contrib/bind-9.5.2/bin/nsupdate/nsupdate.html | 511 + contrib/bind-9.5.2/bin/rndc/include/rndc/os.h | 46 + contrib/bind-9.5.2/bin/rndc/rndc-confgen.8 | 211 + contrib/bind-9.5.2/bin/rndc/rndc-confgen.c | 342 + contrib/bind-9.5.2/bin/rndc/rndc-confgen.html | 188 + contrib/bind-9.5.2/bin/rndc/rndc.8 | 148 + contrib/bind-9.5.2/bin/rndc/rndc.c | 859 ++ contrib/bind-9.5.2/bin/rndc/rndc.conf | 47 + contrib/bind-9.5.2/bin/rndc/rndc.conf.5 | 214 + contrib/bind-9.5.2/bin/rndc/rndc.conf.html | 217 + contrib/bind-9.5.2/bin/rndc/rndc.html | 165 + contrib/bind-9.5.2/bin/rndc/unix/os.c | 70 + contrib/bind-9.5.2/bin/rndc/util.c | 57 + contrib/bind-9.5.2/bin/rndc/util.h | 51 + contrib/bind-9.5.2/bind.keys | 6 + contrib/bind-9.5.2/lib/bind/README | 4 + contrib/bind-9.5.2/lib/bind/api | 3 + contrib/bind-9.5.2/lib/bind/bsd/daemon.c | 81 + contrib/bind-9.5.2/lib/bind/bsd/ftruncate.c | 64 + .../bind-9.5.2/lib/bind/bsd/gettimeofday.c | 64 + contrib/bind-9.5.2/lib/bind/bsd/mktemp.c | 156 + contrib/bind-9.5.2/lib/bind/bsd/putenv.c | 27 + contrib/bind-9.5.2/lib/bind/bsd/readv.c | 39 + contrib/bind-9.5.2/lib/bind/bsd/setenv.c | 151 + contrib/bind-9.5.2/lib/bind/bsd/setitimer.c | 29 + contrib/bind-9.5.2/lib/bind/bsd/strcasecmp.c | 124 + contrib/bind-9.5.2/lib/bind/bsd/strdup.c | 20 + contrib/bind-9.5.2/lib/bind/bsd/strerror.c | 94 + contrib/bind-9.5.2/lib/bind/bsd/strpbrk.c | 70 + contrib/bind-9.5.2/lib/bind/bsd/strsep.c | 88 + contrib/bind-9.5.2/lib/bind/bsd/strtoul.c | 119 + contrib/bind-9.5.2/lib/bind/bsd/utimes.c | 40 + contrib/bind-9.5.2/lib/bind/bsd/writev.c | 89 + contrib/bind-9.5.2/lib/bind/config.h.in | 68 + contrib/bind-9.5.2/lib/bind/dst/dst_api.c | 1048 ++ .../bind-9.5.2/lib/bind/dst/dst_internal.h | 155 + contrib/bind-9.5.2/lib/bind/dst/hmac_link.c | 489 + contrib/bind-9.5.2/lib/bind/dst/md5.h | 108 + contrib/bind-9.5.2/lib/bind/dst/md5_dgst.c | 374 + contrib/bind-9.5.2/lib/bind/dst/md5_locl.h | 193 + contrib/bind-9.5.2/lib/bind/dst/support.c | 342 + .../bind-9.5.2/lib/bind/include/arpa/inet.h | 126 + .../lib/bind/include/arpa/nameser.h | 575 ++ .../lib/bind/include/arpa/nameser_compat.h | 232 + .../bind-9.5.2/lib/bind/include/fd_setsize.h | 10 + contrib/bind-9.5.2/lib/bind/include/hesiod.h | 39 + contrib/bind-9.5.2/lib/bind/include/irp.h | 107 + contrib/bind-9.5.2/lib/bind/include/irs.h | 348 + .../lib/bind/include/isc/assertions.h | 123 + contrib/bind-9.5.2/lib/bind/include/isc/ctl.h | 112 + contrib/bind-9.5.2/lib/bind/include/isc/dst.h | 168 + .../lib/bind/include/isc/eventlib.h | 206 + .../bind-9.5.2/lib/bind/include/isc/heap.h | 49 + .../lib/bind/include/isc/irpmarshall.h | 112 + .../bind-9.5.2/lib/bind/include/isc/list.h | 117 + .../bind-9.5.2/lib/bind/include/isc/logging.h | 113 + .../lib/bind/include/isc/memcluster.h | 50 + .../bind-9.5.2/lib/bind/include/isc/misc.h | 44 + .../lib/bind/include/isc/platform.h.in | 36 + .../bind-9.5.2/lib/bind/include/isc/tree.h | 59 + contrib/bind-9.5.2/lib/bind/include/netdb.h | 582 ++ .../bind-9.5.2/lib/bind/include/netgroup.h | 26 + .../bind-9.5.2/lib/bind/include/res_update.h | 69 + contrib/bind-9.5.2/lib/bind/include/resolv.h | 509 + .../bind-9.5.2/lib/bind/include/resolv_mt.h | 47 + contrib/bind-9.5.2/lib/bind/inet/inet_addr.c | 208 + .../bind-9.5.2/lib/bind/inet/inet_cidr_ntop.c | 263 + .../bind-9.5.2/lib/bind/inet/inet_cidr_pton.c | 277 + contrib/bind-9.5.2/lib/bind/inet/inet_data.c | 46 + contrib/bind-9.5.2/lib/bind/inet/inet_lnaof.c | 65 + .../bind-9.5.2/lib/bind/inet/inet_makeaddr.c | 68 + .../bind-9.5.2/lib/bind/inet/inet_net_ntop.c | 279 + .../bind-9.5.2/lib/bind/inet/inet_net_pton.c | 407 + contrib/bind-9.5.2/lib/bind/inet/inet_neta.c | 89 + contrib/bind-9.5.2/lib/bind/inet/inet_netof.c | 64 + .../bind-9.5.2/lib/bind/inet/inet_network.c | 106 + contrib/bind-9.5.2/lib/bind/inet/inet_ntoa.c | 64 + contrib/bind-9.5.2/lib/bind/inet/inet_ntop.c | 207 + contrib/bind-9.5.2/lib/bind/inet/inet_pton.c | 223 + contrib/bind-9.5.2/lib/bind/inet/nsap_addr.c | 111 + contrib/bind-9.5.2/lib/bind/irs/dns.c | 154 + contrib/bind-9.5.2/lib/bind/irs/dns_gr.c | 294 + contrib/bind-9.5.2/lib/bind/irs/dns_ho.c | 1143 +++ contrib/bind-9.5.2/lib/bind/irs/dns_nw.c | 591 ++ contrib/bind-9.5.2/lib/bind/irs/dns_p.h | 52 + contrib/bind-9.5.2/lib/bind/irs/dns_pr.c | 268 + contrib/bind-9.5.2/lib/bind/irs/dns_pw.c | 232 + contrib/bind-9.5.2/lib/bind/irs/dns_sv.c | 300 + .../bind-9.5.2/lib/bind/irs/gai_strerror.c | 105 + contrib/bind-9.5.2/lib/bind/irs/gen.c | 433 + contrib/bind-9.5.2/lib/bind/irs/gen_gr.c | 493 + contrib/bind-9.5.2/lib/bind/irs/gen_ho.c | 391 + contrib/bind-9.5.2/lib/bind/irs/gen_ng.c | 174 + contrib/bind-9.5.2/lib/bind/irs/gen_nw.c | 264 + contrib/bind-9.5.2/lib/bind/irs/gen_p.h | 113 + contrib/bind-9.5.2/lib/bind/irs/gen_pr.c | 228 + contrib/bind-9.5.2/lib/bind/irs/gen_pw.c | 234 + contrib/bind-9.5.2/lib/bind/irs/gen_sv.c | 229 + contrib/bind-9.5.2/lib/bind/irs/getaddrinfo.c | 1253 +++ contrib/bind-9.5.2/lib/bind/irs/getgrent.c | 224 + contrib/bind-9.5.2/lib/bind/irs/getgrent_r.c | 230 + contrib/bind-9.5.2/lib/bind/irs/gethostent.c | 1070 +++ .../bind-9.5.2/lib/bind/irs/gethostent_r.c | 275 + contrib/bind-9.5.2/lib/bind/irs/getnameinfo.c | 334 + contrib/bind-9.5.2/lib/bind/irs/getnetent.c | 345 + contrib/bind-9.5.2/lib/bind/irs/getnetent_r.c | 234 + contrib/bind-9.5.2/lib/bind/irs/getnetgrent.c | 160 + .../bind-9.5.2/lib/bind/irs/getnetgrent_r.c | 219 + contrib/bind-9.5.2/lib/bind/irs/getprotoent.c | 176 + .../bind-9.5.2/lib/bind/irs/getprotoent_r.c | 223 + contrib/bind-9.5.2/lib/bind/irs/getpwent.c | 201 + contrib/bind-9.5.2/lib/bind/irs/getpwent_r.c | 276 + contrib/bind-9.5.2/lib/bind/irs/getservent.c | 179 + .../bind-9.5.2/lib/bind/irs/getservent_r.c | 242 + contrib/bind-9.5.2/lib/bind/irs/hesiod.c | 505 + contrib/bind-9.5.2/lib/bind/irs/hesiod_p.h | 48 + contrib/bind-9.5.2/lib/bind/irs/irp.c | 583 ++ contrib/bind-9.5.2/lib/bind/irs/irp_gr.c | 357 + contrib/bind-9.5.2/lib/bind/irs/irp_ho.c | 405 + contrib/bind-9.5.2/lib/bind/irs/irp_ng.c | 253 + contrib/bind-9.5.2/lib/bind/irs/irp_nw.c | 348 + contrib/bind-9.5.2/lib/bind/irs/irp_p.h | 60 + contrib/bind-9.5.2/lib/bind/irs/irp_pr.c | 327 + contrib/bind-9.5.2/lib/bind/irs/irp_pw.c | 340 + contrib/bind-9.5.2/lib/bind/irs/irp_sv.c | 346 + contrib/bind-9.5.2/lib/bind/irs/irpmarshall.c | 2301 +++++ contrib/bind-9.5.2/lib/bind/irs/irs_data.c | 246 + contrib/bind-9.5.2/lib/bind/irs/irs_data.h | 63 + contrib/bind-9.5.2/lib/bind/irs/irs_p.h | 51 + contrib/bind-9.5.2/lib/bind/irs/lcl.c | 142 + contrib/bind-9.5.2/lib/bind/irs/lcl_gr.c | 354 + contrib/bind-9.5.2/lib/bind/irs/lcl_ho.c | 578 ++ contrib/bind-9.5.2/lib/bind/irs/lcl_ng.c | 446 + contrib/bind-9.5.2/lib/bind/irs/lcl_nw.c | 373 + contrib/bind-9.5.2/lib/bind/irs/lcl_p.h | 51 + contrib/bind-9.5.2/lib/bind/irs/lcl_pr.c | 294 + contrib/bind-9.5.2/lib/bind/irs/lcl_pw.c | 309 + contrib/bind-9.5.2/lib/bind/irs/lcl_sv.c | 432 + contrib/bind-9.5.2/lib/bind/irs/nis.c | 156 + contrib/bind-9.5.2/lib/bind/irs/nis_gr.c | 354 + contrib/bind-9.5.2/lib/bind/irs/nis_ho.c | 535 ++ contrib/bind-9.5.2/lib/bind/irs/nis_ng.c | 304 + contrib/bind-9.5.2/lib/bind/irs/nis_nw.c | 385 + contrib/bind-9.5.2/lib/bind/irs/nis_p.h | 47 + contrib/bind-9.5.2/lib/bind/irs/nis_pr.c | 302 + contrib/bind-9.5.2/lib/bind/irs/nis_pw.c | 288 + contrib/bind-9.5.2/lib/bind/irs/nis_sv.c | 310 + contrib/bind-9.5.2/lib/bind/irs/nul_ng.c | 127 + contrib/bind-9.5.2/lib/bind/irs/pathnames.h | 52 + contrib/bind-9.5.2/lib/bind/irs/util.c | 109 + contrib/bind-9.5.2/lib/bind/isc/assertions.c | 94 + .../bind-9.5.2/lib/bind/isc/assertions.mdoc | 138 + contrib/bind-9.5.2/lib/bind/isc/base64.c | 322 + contrib/bind-9.5.2/lib/bind/isc/bitncmp.c | 68 + contrib/bind-9.5.2/lib/bind/isc/bitncmp.mdoc | 82 + contrib/bind-9.5.2/lib/bind/isc/ctl_clnt.c | 620 ++ contrib/bind-9.5.2/lib/bind/isc/ctl_p.c | 188 + contrib/bind-9.5.2/lib/bind/isc/ctl_p.h | 28 + contrib/bind-9.5.2/lib/bind/isc/ctl_srvr.c | 787 ++ contrib/bind-9.5.2/lib/bind/isc/ev_connects.c | 369 + contrib/bind-9.5.2/lib/bind/isc/ev_files.c | 277 + contrib/bind-9.5.2/lib/bind/isc/ev_streams.c | 308 + contrib/bind-9.5.2/lib/bind/isc/ev_timers.c | 499 + contrib/bind-9.5.2/lib/bind/isc/ev_waits.c | 247 + contrib/bind-9.5.2/lib/bind/isc/eventlib.c | 933 ++ contrib/bind-9.5.2/lib/bind/isc/eventlib.mdoc | 918 ++ contrib/bind-9.5.2/lib/bind/isc/eventlib_p.h | 281 + contrib/bind-9.5.2/lib/bind/isc/heap.c | 236 + contrib/bind-9.5.2/lib/bind/isc/heap.mdoc | 378 + contrib/bind-9.5.2/lib/bind/isc/hex.c | 119 + contrib/bind-9.5.2/lib/bind/isc/logging.c | 716 ++ contrib/bind-9.5.2/lib/bind/isc/logging.mdoc | 1056 ++ contrib/bind-9.5.2/lib/bind/isc/logging_p.h | 61 + contrib/bind-9.5.2/lib/bind/isc/memcluster.c | 588 ++ .../bind-9.5.2/lib/bind/isc/memcluster.mdoc | 376 + contrib/bind-9.5.2/lib/bind/isc/movefile.c | 37 + contrib/bind-9.5.2/lib/bind/isc/tree.c | 534 ++ contrib/bind-9.5.2/lib/bind/isc/tree.mdoc | 154 + contrib/bind-9.5.2/lib/bind/make/includes.in | 44 + contrib/bind-9.5.2/lib/bind/make/mkdep.in | 147 + contrib/bind-9.5.2/lib/bind/make/rules.in | 177 + contrib/bind-9.5.2/lib/bind/mkinstalldirs | 40 + contrib/bind-9.5.2/lib/bind/nameser/ns_date.c | 129 + contrib/bind-9.5.2/lib/bind/nameser/ns_name.c | 973 ++ .../bind-9.5.2/lib/bind/nameser/ns_netint.c | 58 + .../bind-9.5.2/lib/bind/nameser/ns_parse.c | 211 + .../bind-9.5.2/lib/bind/nameser/ns_print.c | 897 ++ .../lib/bind/nameser/ns_samedomain.c | 207 + contrib/bind-9.5.2/lib/bind/nameser/ns_sign.c | 387 + contrib/bind-9.5.2/lib/bind/nameser/ns_ttl.c | 162 + .../bind-9.5.2/lib/bind/nameser/ns_verify.c | 484 + .../bind/port/freebsd/include/sys/bitypes.h | 37 + contrib/bind-9.5.2/lib/bind/port_after.h.in | 526 + contrib/bind-9.5.2/lib/bind/port_before.h.in | 192 + contrib/bind-9.5.2/lib/bind/resolv/herror.c | 129 + contrib/bind-9.5.2/lib/bind/resolv/mtctxres.c | 129 + contrib/bind-9.5.2/lib/bind/resolv/res_comp.c | 265 + contrib/bind-9.5.2/lib/bind/resolv/res_data.c | 297 + .../bind-9.5.2/lib/bind/resolv/res_debug.c | 1212 +++ .../bind-9.5.2/lib/bind/resolv/res_debug.h | 35 + .../lib/bind/resolv/res_findzonecut.c | 722 ++ contrib/bind-9.5.2/lib/bind/resolv/res_init.c | 801 ++ .../bind-9.5.2/lib/bind/resolv/res_mkquery.c | 303 + .../bind-9.5.2/lib/bind/resolv/res_mkupdate.c | 1162 +++ .../bind-9.5.2/lib/bind/resolv/res_mkupdate.h | 25 + .../bind-9.5.2/lib/bind/resolv/res_private.h | 22 + .../bind-9.5.2/lib/bind/resolv/res_query.c | 440 + contrib/bind-9.5.2/lib/bind/resolv/res_send.c | 1108 +++ .../lib/bind/resolv/res_sendsigned.c | 170 + .../bind-9.5.2/lib/bind/resolv/res_update.c | 213 + contrib/bind-9.5.2/lib/bind9/api | 3 + contrib/bind-9.5.2/lib/bind9/check.c | 2250 +++++ contrib/bind-9.5.2/lib/bind9/getaddresses.c | 231 + .../lib/bind9/include/bind9/check.h | 57 + .../lib/bind9/include/bind9/getaddresses.h | 61 + .../lib/bind9/include/bind9/version.h | 28 + contrib/bind-9.5.2/lib/bind9/version.c | 28 + contrib/bind-9.5.2/lib/dns/acache.c | 1782 ++++ contrib/bind-9.5.2/lib/dns/acl.c | 623 ++ contrib/bind-9.5.2/lib/dns/adb.c | 3631 +++++++ contrib/bind-9.5.2/lib/dns/api | 3 + contrib/bind-9.5.2/lib/dns/byaddr.c | 316 + contrib/bind-9.5.2/lib/dns/cache.c | 1098 +++ contrib/bind-9.5.2/lib/dns/callbacks.c | 113 + contrib/bind-9.5.2/lib/dns/compress.c | 341 + contrib/bind-9.5.2/lib/dns/db.c | 857 ++ contrib/bind-9.5.2/lib/dns/dbiterator.c | 143 + contrib/bind-9.5.2/lib/dns/dbtable.c | 291 + contrib/bind-9.5.2/lib/dns/diff.c | 554 ++ contrib/bind-9.5.2/lib/dns/dispatch.c | 3324 +++++++ contrib/bind-9.5.2/lib/dns/dlz.c | 510 + contrib/bind-9.5.2/lib/dns/dnssec.c | 892 ++ contrib/bind-9.5.2/lib/dns/ds.c | 104 + contrib/bind-9.5.2/lib/dns/dst_api.c | 1265 +++ contrib/bind-9.5.2/lib/dns/dst_internal.h | 205 + contrib/bind-9.5.2/lib/dns/dst_lib.c | 67 + contrib/bind-9.5.2/lib/dns/dst_openssl.h | 34 + contrib/bind-9.5.2/lib/dns/dst_parse.c | 508 + contrib/bind-9.5.2/lib/dns/dst_parse.h | 131 + contrib/bind-9.5.2/lib/dns/dst_result.c | 88 + contrib/bind-9.5.2/lib/dns/forward.c | 199 + contrib/bind-9.5.2/lib/dns/gen-unix.h | 97 + contrib/bind-9.5.2/lib/dns/gen-win32.h | 290 + contrib/bind-9.5.2/lib/dns/gen.c | 884 ++ contrib/bind-9.5.2/lib/dns/gssapi_link.c | 309 + contrib/bind-9.5.2/lib/dns/gssapictx.c | 738 ++ contrib/bind-9.5.2/lib/dns/hmac_link.c | 1681 ++++ .../bind-9.5.2/lib/dns/include/dns/acache.h | 445 + contrib/bind-9.5.2/lib/dns/include/dns/acl.h | 222 + contrib/bind-9.5.2/lib/dns/include/dns/adb.h | 634 ++ contrib/bind-9.5.2/lib/dns/include/dns/bit.h | 39 + .../bind-9.5.2/lib/dns/include/dns/byaddr.h | 171 + .../bind-9.5.2/lib/dns/include/dns/cache.h | 253 + .../lib/dns/include/dns/callbacks.h | 87 + contrib/bind-9.5.2/lib/dns/include/dns/cert.h | 69 + .../bind-9.5.2/lib/dns/include/dns/compress.h | 269 + contrib/bind-9.5.2/lib/dns/include/dns/db.h | 1338 +++ .../lib/dns/include/dns/dbiterator.h | 297 + .../bind-9.5.2/lib/dns/include/dns/dbtable.h | 165 + contrib/bind-9.5.2/lib/dns/include/dns/diff.h | 280 + .../bind-9.5.2/lib/dns/include/dns/dispatch.h | 501 + contrib/bind-9.5.2/lib/dns/include/dns/dlz.h | 290 + .../bind-9.5.2/lib/dns/include/dns/dnssec.h | 183 + contrib/bind-9.5.2/lib/dns/include/dns/ds.h | 63 + .../bind-9.5.2/lib/dns/include/dns/events.h | 76 + .../lib/dns/include/dns/fixedname.h | 86 + .../bind-9.5.2/lib/dns/include/dns/forward.h | 118 + .../bind-9.5.2/lib/dns/include/dns/iptable.h | 70 + .../bind-9.5.2/lib/dns/include/dns/journal.h | 276 + .../bind-9.5.2/lib/dns/include/dns/keyflags.h | 54 + .../bind-9.5.2/lib/dns/include/dns/keytable.h | 255 + .../lib/dns/include/dns/keyvalues.h | 98 + contrib/bind-9.5.2/lib/dns/include/dns/lib.h | 45 + contrib/bind-9.5.2/lib/dns/include/dns/log.h | 107 + .../bind-9.5.2/lib/dns/include/dns/lookup.h | 137 + .../bind-9.5.2/lib/dns/include/dns/master.h | 277 + .../lib/dns/include/dns/masterdump.h | 334 + .../bind-9.5.2/lib/dns/include/dns/message.h | 1343 +++ contrib/bind-9.5.2/lib/dns/include/dns/name.h | 1297 +++ .../bind-9.5.2/lib/dns/include/dns/ncache.h | 159 + contrib/bind-9.5.2/lib/dns/include/dns/nsec.h | 69 + .../bind-9.5.2/lib/dns/include/dns/opcode.h | 51 + .../bind-9.5.2/lib/dns/include/dns/order.h | 99 + contrib/bind-9.5.2/lib/dns/include/dns/peer.h | 219 + .../bind-9.5.2/lib/dns/include/dns/portlist.h | 101 + contrib/bind-9.5.2/lib/dns/include/dns/rbt.h | 925 ++ .../bind-9.5.2/lib/dns/include/dns/rcode.h | 98 + .../bind-9.5.2/lib/dns/include/dns/rdata.h | 702 ++ .../lib/dns/include/dns/rdataclass.h | 81 + .../lib/dns/include/dns/rdatalist.h | 124 + .../bind-9.5.2/lib/dns/include/dns/rdataset.h | 597 ++ .../lib/dns/include/dns/rdatasetiter.h | 170 + .../lib/dns/include/dns/rdataslab.h | 163 + .../lib/dns/include/dns/rdatatype.h | 83 + .../bind-9.5.2/lib/dns/include/dns/request.h | 374 + .../bind-9.5.2/lib/dns/include/dns/resolver.h | 513 + .../bind-9.5.2/lib/dns/include/dns/result.h | 190 + .../bind-9.5.2/lib/dns/include/dns/rootns.h | 45 + contrib/bind-9.5.2/lib/dns/include/dns/sdb.h | 209 + contrib/bind-9.5.2/lib/dns/include/dns/sdlz.h | 266 + .../bind-9.5.2/lib/dns/include/dns/secalg.h | 71 + .../bind-9.5.2/lib/dns/include/dns/secproto.h | 71 + contrib/bind-9.5.2/lib/dns/include/dns/soa.h | 81 + contrib/bind-9.5.2/lib/dns/include/dns/ssu.h | 168 + .../bind-9.5.2/lib/dns/include/dns/stats.h | 364 + .../bind-9.5.2/lib/dns/include/dns/tcpmsg.h | 147 + contrib/bind-9.5.2/lib/dns/include/dns/time.h | 72 + .../bind-9.5.2/lib/dns/include/dns/timer.h | 52 + contrib/bind-9.5.2/lib/dns/include/dns/tkey.h | 250 + contrib/bind-9.5.2/lib/dns/include/dns/tsig.h | 257 + contrib/bind-9.5.2/lib/dns/include/dns/ttl.h | 78 + .../bind-9.5.2/lib/dns/include/dns/types.h | 340 + .../lib/dns/include/dns/validator.h | 247 + .../bind-9.5.2/lib/dns/include/dns/version.h | 28 + contrib/bind-9.5.2/lib/dns/include/dns/view.h | 879 ++ .../bind-9.5.2/lib/dns/include/dns/xfrin.h | 111 + contrib/bind-9.5.2/lib/dns/include/dns/zone.h | 1681 ++++ .../bind-9.5.2/lib/dns/include/dns/zonekey.h | 42 + contrib/bind-9.5.2/lib/dns/include/dns/zt.h | 183 + contrib/bind-9.5.2/lib/dns/include/dst/dst.h | 634 ++ .../bind-9.5.2/lib/dns/include/dst/gssapi.h | 207 + contrib/bind-9.5.2/lib/dns/include/dst/lib.h | 41 + .../bind-9.5.2/lib/dns/include/dst/result.h | 70 + contrib/bind-9.5.2/lib/dns/iptable.c | 188 + contrib/bind-9.5.2/lib/dns/journal.c | 2182 +++++ contrib/bind-9.5.2/lib/dns/key.c | 147 + contrib/bind-9.5.2/lib/dns/keytable.c | 395 + contrib/bind-9.5.2/lib/dns/lib.c | 65 + contrib/bind-9.5.2/lib/dns/log.c | 98 + contrib/bind-9.5.2/lib/dns/lookup.c | 497 + contrib/bind-9.5.2/lib/dns/master.c | 2835 ++++++ contrib/bind-9.5.2/lib/dns/masterdump.c | 1737 ++++ contrib/bind-9.5.2/lib/dns/message.c | 3373 +++++++ contrib/bind-9.5.2/lib/dns/name.c | 2408 +++++ contrib/bind-9.5.2/lib/dns/ncache.c | 559 ++ contrib/bind-9.5.2/lib/dns/nsec.c | 220 + contrib/bind-9.5.2/lib/dns/openssl_link.c | 270 + contrib/bind-9.5.2/lib/dns/openssldh_link.c | 637 ++ contrib/bind-9.5.2/lib/dns/openssldsa_link.c | 475 + contrib/bind-9.5.2/lib/dns/opensslrsa_link.c | 630 ++ contrib/bind-9.5.2/lib/dns/order.c | 167 + contrib/bind-9.5.2/lib/dns/peer.c | 712 ++ contrib/bind-9.5.2/lib/dns/portlist.c | 266 + contrib/bind-9.5.2/lib/dns/rbt.c | 2548 +++++ contrib/bind-9.5.2/lib/dns/rbtdb.c | 7631 +++++++++++++++ contrib/bind-9.5.2/lib/dns/rbtdb.h | 44 + contrib/bind-9.5.2/lib/dns/rbtdb64.c | 23 + contrib/bind-9.5.2/lib/dns/rbtdb64.h | 45 + contrib/bind-9.5.2/lib/dns/rcode.c | 474 + contrib/bind-9.5.2/lib/dns/rdata.c | 1746 ++++ .../lib/dns/rdata/any_255/tsig_250.c | 597 ++ .../lib/dns/rdata/any_255/tsig_250.h | 38 + contrib/bind-9.5.2/lib/dns/rdata/ch_3/a_1.c | 316 + contrib/bind-9.5.2/lib/dns/rdata/ch_3/a_1.h | 34 + .../lib/dns/rdata/generic/afsdb_18.c | 309 + .../lib/dns/rdata/generic/afsdb_18.h | 34 + .../lib/dns/rdata/generic/cert_37.c | 280 + .../lib/dns/rdata/generic/cert_37.h | 34 + .../lib/dns/rdata/generic/cname_5.c | 232 + .../lib/dns/rdata/generic/cname_5.h | 29 + .../lib/dns/rdata/generic/dlv_32769.c | 321 + .../lib/dns/rdata/generic/dlv_32769.h | 33 + .../lib/dns/rdata/generic/dname_39.c | 233 + .../lib/dns/rdata/generic/dname_39.h | 32 + .../lib/dns/rdata/generic/dnskey_48.c | 312 + .../lib/dns/rdata/generic/dnskey_48.h | 37 + .../bind-9.5.2/lib/dns/rdata/generic/ds_43.c | 321 + .../bind-9.5.2/lib/dns/rdata/generic/ds_43.h | 35 + .../lib/dns/rdata/generic/gpos_27.c | 252 + .../lib/dns/rdata/generic/gpos_27.h | 37 + .../lib/dns/rdata/generic/hinfo_13.c | 224 + .../lib/dns/rdata/generic/hinfo_13.h | 32 + .../lib/dns/rdata/generic/ipseckey_45.c | 463 + .../lib/dns/rdata/generic/ipseckey_45.h | 35 + .../lib/dns/rdata/generic/isdn_20.c | 234 + .../lib/dns/rdata/generic/isdn_20.h | 35 + .../bind-9.5.2/lib/dns/rdata/generic/key_25.c | 312 + .../bind-9.5.2/lib/dns/rdata/generic/key_25.h | 37 + .../bind-9.5.2/lib/dns/rdata/generic/loc_29.c | 799 ++ .../bind-9.5.2/lib/dns/rdata/generic/loc_29.h | 43 + .../bind-9.5.2/lib/dns/rdata/generic/mb_7.c | 234 + .../bind-9.5.2/lib/dns/rdata/generic/mb_7.h | 30 + .../bind-9.5.2/lib/dns/rdata/generic/md_3.c | 236 + .../bind-9.5.2/lib/dns/rdata/generic/md_3.h | 31 + .../bind-9.5.2/lib/dns/rdata/generic/mf_4.c | 235 + .../bind-9.5.2/lib/dns/rdata/generic/mf_4.h | 30 + .../bind-9.5.2/lib/dns/rdata/generic/mg_8.c | 230 + .../bind-9.5.2/lib/dns/rdata/generic/mg_8.h | 30 + .../lib/dns/rdata/generic/minfo_14.c | 324 + .../lib/dns/rdata/generic/minfo_14.h | 31 + .../bind-9.5.2/lib/dns/rdata/generic/mr_9.c | 231 + .../bind-9.5.2/lib/dns/rdata/generic/mr_9.h | 30 + .../bind-9.5.2/lib/dns/rdata/generic/mx_15.c | 319 + .../bind-9.5.2/lib/dns/rdata/generic/mx_15.h | 31 + .../bind-9.5.2/lib/dns/rdata/generic/ns_2.c | 251 + .../bind-9.5.2/lib/dns/rdata/generic/ns_2.h | 31 + .../lib/dns/rdata/generic/nsec_47.c | 366 + .../lib/dns/rdata/generic/nsec_47.h | 34 + .../lib/dns/rdata/generic/null_10.c | 192 + .../lib/dns/rdata/generic/null_10.h | 32 + .../bind-9.5.2/lib/dns/rdata/generic/nxt_30.c | 329 + .../bind-9.5.2/lib/dns/rdata/generic/nxt_30.h | 34 + .../bind-9.5.2/lib/dns/rdata/generic/opt_41.c | 280 + .../bind-9.5.2/lib/dns/rdata/generic/opt_41.h | 55 + .../lib/dns/rdata/generic/proforma.c | 173 + .../lib/dns/rdata/generic/proforma.h | 30 + .../bind-9.5.2/lib/dns/rdata/generic/ptr_12.c | 291 + .../bind-9.5.2/lib/dns/rdata/generic/ptr_12.h | 30 + .../bind-9.5.2/lib/dns/rdata/generic/rp_17.c | 314 + .../bind-9.5.2/lib/dns/rdata/generic/rp_17.h | 34 + .../lib/dns/rdata/generic/rrsig_46.c | 551 ++ .../lib/dns/rdata/generic/rrsig_46.h | 41 + .../bind-9.5.2/lib/dns/rdata/generic/rt_21.c | 311 + .../bind-9.5.2/lib/dns/rdata/generic/rt_21.h | 33 + .../bind-9.5.2/lib/dns/rdata/generic/sig_24.c | 578 ++ .../bind-9.5.2/lib/dns/rdata/generic/sig_24.h | 42 + .../bind-9.5.2/lib/dns/rdata/generic/soa_6.c | 444 + .../bind-9.5.2/lib/dns/rdata/generic/soa_6.h | 37 + .../bind-9.5.2/lib/dns/rdata/generic/spf_99.c | 238 + .../bind-9.5.2/lib/dns/rdata/generic/spf_99.h | 51 + .../lib/dns/rdata/generic/sshfp_44.c | 262 + .../lib/dns/rdata/generic/sshfp_44.h | 35 + .../lib/dns/rdata/generic/tkey_249.c | 555 ++ .../lib/dns/rdata/generic/tkey_249.h | 41 + .../bind-9.5.2/lib/dns/rdata/generic/txt_16.c | 238 + .../bind-9.5.2/lib/dns/rdata/generic/txt_16.h | 52 + .../lib/dns/rdata/generic/unspec_103.c | 189 + .../lib/dns/rdata/generic/unspec_103.h | 31 + .../bind-9.5.2/lib/dns/rdata/generic/x25_19.c | 219 + .../bind-9.5.2/lib/dns/rdata/generic/x25_19.h | 33 + contrib/bind-9.5.2/lib/dns/rdata/hs_4/a_1.c | 232 + contrib/bind-9.5.2/lib/dns/rdata/hs_4/a_1.h | 29 + contrib/bind-9.5.2/lib/dns/rdata/in_1/a6_38.c | 461 + contrib/bind-9.5.2/lib/dns/rdata/in_1/a6_38.h | 34 + contrib/bind-9.5.2/lib/dns/rdata/in_1/a_1.c | 236 + contrib/bind-9.5.2/lib/dns/rdata/in_1/a_1.h | 29 + .../bind-9.5.2/lib/dns/rdata/in_1/aaaa_28.c | 233 + .../bind-9.5.2/lib/dns/rdata/in_1/aaaa_28.h | 31 + .../bind-9.5.2/lib/dns/rdata/in_1/apl_42.c | 453 + .../bind-9.5.2/lib/dns/rdata/in_1/apl_42.h | 56 + .../bind-9.5.2/lib/dns/rdata/in_1/dhcid_49.c | 229 + .../bind-9.5.2/lib/dns/rdata/in_1/dhcid_49.h | 30 + contrib/bind-9.5.2/lib/dns/rdata/in_1/kx_36.c | 288 + contrib/bind-9.5.2/lib/dns/rdata/in_1/kx_36.h | 33 + .../bind-9.5.2/lib/dns/rdata/in_1/naptr_35.c | 578 ++ .../bind-9.5.2/lib/dns/rdata/in_1/naptr_35.h | 40 + .../lib/dns/rdata/in_1/nsap-ptr_23.c | 245 + .../lib/dns/rdata/in_1/nsap-ptr_23.h | 32 + .../bind-9.5.2/lib/dns/rdata/in_1/nsap_22.c | 255 + .../bind-9.5.2/lib/dns/rdata/in_1/nsap_22.h | 33 + contrib/bind-9.5.2/lib/dns/rdata/in_1/px_26.c | 374 + contrib/bind-9.5.2/lib/dns/rdata/in_1/px_26.h | 34 + .../bind-9.5.2/lib/dns/rdata/in_1/srv_33.c | 373 + .../bind-9.5.2/lib/dns/rdata/in_1/srv_33.h | 37 + .../bind-9.5.2/lib/dns/rdata/in_1/wks_11.c | 351 + .../bind-9.5.2/lib/dns/rdata/in_1/wks_11.h | 32 + .../bind-9.5.2/lib/dns/rdata/rdatastructpre.h | 42 + .../bind-9.5.2/lib/dns/rdata/rdatastructsuf.h | 22 + contrib/bind-9.5.2/lib/dns/rdatalist.c | 239 + contrib/bind-9.5.2/lib/dns/rdatalist_p.h | 57 + contrib/bind-9.5.2/lib/dns/rdataset.c | 709 ++ contrib/bind-9.5.2/lib/dns/rdatasetiter.c | 80 + contrib/bind-9.5.2/lib/dns/rdataslab.c | 1041 ++ contrib/bind-9.5.2/lib/dns/request.c | 1497 +++ contrib/bind-9.5.2/lib/dns/resolver.c | 7829 +++++++++++++++ contrib/bind-9.5.2/lib/dns/result.c | 276 + contrib/bind-9.5.2/lib/dns/rootns.c | 518 + contrib/bind-9.5.2/lib/dns/sdb.c | 1545 +++ contrib/bind-9.5.2/lib/dns/sdlz.c | 1793 ++++ contrib/bind-9.5.2/lib/dns/soa.c | 111 + contrib/bind-9.5.2/lib/dns/spnego.asn1 | 52 + contrib/bind-9.5.2/lib/dns/spnego.c | 1788 ++++ contrib/bind-9.5.2/lib/dns/spnego.h | 71 + contrib/bind-9.5.2/lib/dns/spnego_asn1.c | 885 ++ contrib/bind-9.5.2/lib/dns/spnego_asn1.pl | 200 + contrib/bind-9.5.2/lib/dns/ssu.c | 411 + contrib/bind-9.5.2/lib/dns/stats.c | 404 + contrib/bind-9.5.2/lib/dns/tcpmsg.c | 243 + contrib/bind-9.5.2/lib/dns/time.c | 174 + contrib/bind-9.5.2/lib/dns/timer.c | 60 + contrib/bind-9.5.2/lib/dns/tkey.c | 1419 +++ contrib/bind-9.5.2/lib/dns/tsig.c | 1549 +++ contrib/bind-9.5.2/lib/dns/ttl.c | 216 + contrib/bind-9.5.2/lib/dns/validator.c | 3184 ++++++ contrib/bind-9.5.2/lib/dns/version.c | 28 + contrib/bind-9.5.2/lib/dns/view.c | 1468 +++ contrib/bind-9.5.2/lib/dns/xfrin.c | 1532 +++ contrib/bind-9.5.2/lib/dns/zone.c | 8494 +++++++++++++++++ contrib/bind-9.5.2/lib/dns/zonekey.c | 55 + contrib/bind-9.5.2/lib/dns/zt.c | 411 + contrib/bind-9.5.2/lib/isc/api | 3 + contrib/bind-9.5.2/lib/isc/assertions.c | 97 + contrib/bind-9.5.2/lib/isc/base64.c | 250 + contrib/bind-9.5.2/lib/isc/bitstring.c | 127 + contrib/bind-9.5.2/lib/isc/buffer.c | 481 + contrib/bind-9.5.2/lib/isc/bufferlist.c | 64 + contrib/bind-9.5.2/lib/isc/commandline.c | 222 + contrib/bind-9.5.2/lib/isc/entropy.c | 1274 +++ contrib/bind-9.5.2/lib/isc/error.c | 106 + contrib/bind-9.5.2/lib/isc/event.c | 88 + contrib/bind-9.5.2/lib/isc/fsaccess.c | 102 + contrib/bind-9.5.2/lib/isc/hash.c | 390 + contrib/bind-9.5.2/lib/isc/heap.c | 262 + contrib/bind-9.5.2/lib/isc/hex.c | 201 + contrib/bind-9.5.2/lib/isc/hmacmd5.c | 118 + contrib/bind-9.5.2/lib/isc/hmacsha.c | 438 + contrib/bind-9.5.2/lib/isc/httpd.c | 987 ++ contrib/bind-9.5.2/lib/isc/include/isc/app.h | 212 + .../lib/isc/include/isc/assertions.h | 124 + .../bind-9.5.2/lib/isc/include/isc/base64.h | 99 + .../lib/isc/include/isc/bitstring.h | 157 + .../bind-9.5.2/lib/isc/include/isc/boolean.h | 31 + .../bind-9.5.2/lib/isc/include/isc/buffer.h | 876 ++ .../lib/isc/include/isc/bufferlist.h | 86 + .../lib/isc/include/isc/commandline.h | 50 + .../bind-9.5.2/lib/isc/include/isc/entropy.h | 314 + .../bind-9.5.2/lib/isc/include/isc/error.h | 62 + .../bind-9.5.2/lib/isc/include/isc/event.h | 121 + .../lib/isc/include/isc/eventclass.h | 53 + contrib/bind-9.5.2/lib/isc/include/isc/file.h | 256 + .../lib/isc/include/isc/formatcheck.h | 40 + .../bind-9.5.2/lib/isc/include/isc/fsaccess.h | 178 + contrib/bind-9.5.2/lib/isc/include/isc/hash.h | 185 + contrib/bind-9.5.2/lib/isc/include/isc/heap.h | 170 + contrib/bind-9.5.2/lib/isc/include/isc/hex.h | 98 + .../bind-9.5.2/lib/isc/include/isc/hmacmd5.h | 63 + .../bind-9.5.2/lib/isc/include/isc/hmacsha.h | 156 + .../bind-9.5.2/lib/isc/include/isc/httpd.h | 64 + .../lib/isc/include/isc/interfaceiter.h | 133 + contrib/bind-9.5.2/lib/isc/include/isc/ipv6.h | 148 + contrib/bind-9.5.2/lib/isc/include/isc/lang.h | 33 + contrib/bind-9.5.2/lib/isc/include/isc/lex.h | 431 + contrib/bind-9.5.2/lib/isc/include/isc/lfsr.h | 130 + contrib/bind-9.5.2/lib/isc/include/isc/lib.h | 41 + contrib/bind-9.5.2/lib/isc/include/isc/list.h | 184 + contrib/bind-9.5.2/lib/isc/include/isc/log.h | 914 ++ .../bind-9.5.2/lib/isc/include/isc/magic.h | 41 + contrib/bind-9.5.2/lib/isc/include/isc/md5.h | 73 + contrib/bind-9.5.2/lib/isc/include/isc/mem.h | 622 ++ .../bind-9.5.2/lib/isc/include/isc/msgcat.h | 131 + contrib/bind-9.5.2/lib/isc/include/isc/msgs.h | 194 + .../lib/isc/include/isc/mutexblock.h | 71 + .../bind-9.5.2/lib/isc/include/isc/netaddr.h | 180 + .../bind-9.5.2/lib/isc/include/isc/netscope.h | 43 + .../lib/isc/include/isc/ondestroy.h | 116 + contrib/bind-9.5.2/lib/isc/include/isc/os.h | 38 + .../bind-9.5.2/lib/isc/include/isc/parseint.h | 64 + .../lib/isc/include/isc/platform.h.in | 339 + .../bind-9.5.2/lib/isc/include/isc/portset.h | 141 + .../bind-9.5.2/lib/isc/include/isc/print.h | 87 + .../bind-9.5.2/lib/isc/include/isc/quota.h | 119 + .../bind-9.5.2/lib/isc/include/isc/radix.h | 240 + .../bind-9.5.2/lib/isc/include/isc/random.h | 62 + .../lib/isc/include/isc/ratelimiter.h | 134 + .../bind-9.5.2/lib/isc/include/isc/refcount.h | 233 + .../bind-9.5.2/lib/isc/include/isc/region.h | 99 + .../bind-9.5.2/lib/isc/include/isc/resource.h | 97 + .../bind-9.5.2/lib/isc/include/isc/result.h | 106 + .../lib/isc/include/isc/resultclass.h | 50 + .../bind-9.5.2/lib/isc/include/isc/rwlock.h | 135 + .../bind-9.5.2/lib/isc/include/isc/serial.h | 75 + contrib/bind-9.5.2/lib/isc/include/isc/sha1.h | 59 + contrib/bind-9.5.2/lib/isc/include/isc/sha2.h | 132 + .../bind-9.5.2/lib/isc/include/isc/sockaddr.h | 241 + .../bind-9.5.2/lib/isc/include/isc/socket.h | 1007 ++ .../bind-9.5.2/lib/isc/include/isc/stats.h | 121 + .../bind-9.5.2/lib/isc/include/isc/stdio.h | 77 + .../bind-9.5.2/lib/isc/include/isc/stdlib.h | 40 + .../bind-9.5.2/lib/isc/include/isc/string.h | 231 + .../bind-9.5.2/lib/isc/include/isc/symtab.h | 131 + contrib/bind-9.5.2/lib/isc/include/isc/task.h | 624 ++ .../bind-9.5.2/lib/isc/include/isc/taskpool.h | 105 + .../bind-9.5.2/lib/isc/include/isc/timer.h | 344 + .../bind-9.5.2/lib/isc/include/isc/types.h | 124 + contrib/bind-9.5.2/lib/isc/include/isc/util.h | 233 + .../bind-9.5.2/lib/isc/include/isc/version.h | 28 + contrib/bind-9.5.2/lib/isc/include/isc/xml.h | 41 + contrib/bind-9.5.2/lib/isc/inet_aton.c | 196 + contrib/bind-9.5.2/lib/isc/inet_ntop.c | 199 + contrib/bind-9.5.2/lib/isc/inet_pton.c | 214 + contrib/bind-9.5.2/lib/isc/lex.c | 959 ++ contrib/bind-9.5.2/lib/isc/lfsr.c | 161 + contrib/bind-9.5.2/lib/isc/lib.c | 79 + contrib/bind-9.5.2/lib/isc/log.c | 1762 ++++ contrib/bind-9.5.2/lib/isc/md5.c | 251 + contrib/bind-9.5.2/lib/isc/mem.c | 2193 +++++ contrib/bind-9.5.2/lib/isc/mutexblock.c | 59 + contrib/bind-9.5.2/lib/isc/netaddr.c | 436 + contrib/bind-9.5.2/lib/isc/netscope.c | 76 + contrib/bind-9.5.2/lib/isc/nls/msgcat.c | 131 + .../lib/isc/noatomic/include/isc/atomic.h | 24 + .../bind-9.5.2/lib/isc/nothreads/condition.c | 24 + .../lib/isc/nothreads/include/isc/condition.h | 59 + .../lib/isc/nothreads/include/isc/mutex.h | 39 + .../lib/isc/nothreads/include/isc/once.h | 32 + .../lib/isc/nothreads/include/isc/thread.h | 35 + contrib/bind-9.5.2/lib/isc/nothreads/mutex.c | 25 + contrib/bind-9.5.2/lib/isc/nothreads/thread.c | 28 + contrib/bind-9.5.2/lib/isc/ondestroy.c | 85 + contrib/bind-9.5.2/lib/isc/parseint.c | 72 + contrib/bind-9.5.2/lib/isc/portset.c | 143 + contrib/bind-9.5.2/lib/isc/print.c | 624 ++ .../bind-9.5.2/lib/isc/pthreads/condition.c | 74 + .../lib/isc/pthreads/include/isc/condition.h | 65 + .../lib/isc/pthreads/include/isc/mutex.h | 145 + .../lib/isc/pthreads/include/isc/once.h | 50 + .../lib/isc/pthreads/include/isc/thread.h | 60 + contrib/bind-9.5.2/lib/isc/pthreads/mutex.c | 272 + contrib/bind-9.5.2/lib/isc/pthreads/thread.c | 76 + contrib/bind-9.5.2/lib/isc/quota.c | 101 + contrib/bind-9.5.2/lib/isc/radix.c | 705 ++ contrib/bind-9.5.2/lib/isc/random.c | 113 + contrib/bind-9.5.2/lib/isc/ratelimiter.c | 328 + contrib/bind-9.5.2/lib/isc/refcount.c | 37 + contrib/bind-9.5.2/lib/isc/region.c | 45 + contrib/bind-9.5.2/lib/isc/result.c | 212 + contrib/bind-9.5.2/lib/isc/rwlock.c | 808 ++ contrib/bind-9.5.2/lib/isc/serial.c | 59 + contrib/bind-9.5.2/lib/isc/sha1.c | 315 + contrib/bind-9.5.2/lib/isc/sha2.c | 1234 +++ contrib/bind-9.5.2/lib/isc/sockaddr.c | 503 + contrib/bind-9.5.2/lib/isc/stats.c | 326 + contrib/bind-9.5.2/lib/isc/string.c | 270 + contrib/bind-9.5.2/lib/isc/strtoul.c | 129 + contrib/bind-9.5.2/lib/isc/symtab.c | 252 + contrib/bind-9.5.2/lib/isc/task.c | 1376 +++ contrib/bind-9.5.2/lib/isc/task_p.h | 31 + contrib/bind-9.5.2/lib/isc/taskpool.c | 96 + contrib/bind-9.5.2/lib/isc/timer.c | 933 ++ contrib/bind-9.5.2/lib/isc/timer_p.h | 31 + contrib/bind-9.5.2/lib/isc/unix/app.c | 684 ++ contrib/bind-9.5.2/lib/isc/unix/dir.c | 251 + contrib/bind-9.5.2/lib/isc/unix/entropy.c | 605 ++ .../bind-9.5.2/lib/isc/unix/errno2result.c | 123 + .../bind-9.5.2/lib/isc/unix/errno2result.h | 39 + contrib/bind-9.5.2/lib/isc/unix/file.c | 444 + contrib/bind-9.5.2/lib/isc/unix/fsaccess.c | 93 + .../lib/isc/unix/ifiter_getifaddrs.c | 185 + .../bind-9.5.2/lib/isc/unix/ifiter_ioctl.c | 1029 ++ .../bind-9.5.2/lib/isc/unix/ifiter_sysctl.c | 302 + .../bind-9.5.2/lib/isc/unix/include/isc/dir.h | 94 + .../bind-9.5.2/lib/isc/unix/include/isc/int.h | 55 + .../lib/isc/unix/include/isc/keyboard.h | 52 + .../bind-9.5.2/lib/isc/unix/include/isc/net.h | 364 + .../lib/isc/unix/include/isc/netdb.h | 57 + .../lib/isc/unix/include/isc/offset.h | 46 + .../lib/isc/unix/include/isc/stat.h | 52 + .../lib/isc/unix/include/isc/stdtime.h | 60 + .../lib/isc/unix/include/isc/strerror.h | 45 + .../lib/isc/unix/include/isc/syslog.h | 47 + .../lib/isc/unix/include/isc/time.h | 332 + .../bind-9.5.2/lib/isc/unix/interfaceiter.c | 222 + contrib/bind-9.5.2/lib/isc/unix/ipv6.c | 27 + contrib/bind-9.5.2/lib/isc/unix/keyboard.c | 126 + contrib/bind-9.5.2/lib/isc/unix/net.c | 524 + contrib/bind-9.5.2/lib/isc/unix/os.c | 94 + contrib/bind-9.5.2/lib/isc/unix/resource.c | 231 + contrib/bind-9.5.2/lib/isc/unix/socket.c | 5555 +++++++++++ contrib/bind-9.5.2/lib/isc/unix/socket_p.h | 32 + contrib/bind-9.5.2/lib/isc/unix/stdio.c | 117 + contrib/bind-9.5.2/lib/isc/unix/stdtime.c | 86 + contrib/bind-9.5.2/lib/isc/unix/strerror.c | 74 + contrib/bind-9.5.2/lib/isc/unix/syslog.c | 84 + contrib/bind-9.5.2/lib/isc/unix/time.c | 438 + contrib/bind-9.5.2/lib/isc/version.c | 28 + .../lib/isc/x86_32/include/isc/atomic.h | 176 + .../lib/isc/x86_64/include/isc/atomic.h | 123 + contrib/bind-9.5.2/lib/isccc/alist.c | 312 + contrib/bind-9.5.2/lib/isccc/api | 3 + contrib/bind-9.5.2/lib/isccc/base64.c | 78 + contrib/bind-9.5.2/lib/isccc/cc.c | 831 ++ contrib/bind-9.5.2/lib/isccc/ccmsg.c | 235 + .../lib/isccc/include/isccc/alist.h | 87 + .../lib/isccc/include/isccc/base64.h | 85 + .../bind-9.5.2/lib/isccc/include/isccc/cc.h | 122 + .../lib/isccc/include/isccc/ccmsg.h | 148 + .../lib/isccc/include/isccc/events.h | 50 + .../bind-9.5.2/lib/isccc/include/isccc/lib.h | 55 + .../lib/isccc/include/isccc/result.h | 73 + .../lib/isccc/include/isccc/sexpr.h | 124 + .../lib/isccc/include/isccc/symtab.h | 135 + .../lib/isccc/include/isccc/symtype.h | 44 + .../lib/isccc/include/isccc/types.h | 59 + .../bind-9.5.2/lib/isccc/include/isccc/util.h | 225 + .../lib/isccc/include/isccc/version.h | 28 + contrib/bind-9.5.2/lib/isccc/lib.c | 78 + contrib/bind-9.5.2/lib/isccc/result.c | 85 + contrib/bind-9.5.2/lib/isccc/sexpr.c | 325 + contrib/bind-9.5.2/lib/isccc/symtab.c | 293 + contrib/bind-9.5.2/lib/isccc/version.c | 28 + contrib/bind-9.5.2/lib/isccfg/aclconf.c | 437 + contrib/bind-9.5.2/lib/isccfg/api | 3 + .../lib/isccfg/include/isccfg/aclconf.h | 75 + .../lib/isccfg/include/isccfg/cfg.h | 425 + .../lib/isccfg/include/isccfg/grammar.h | 452 + .../lib/isccfg/include/isccfg/log.h | 55 + .../lib/isccfg/include/isccfg/namedconf.h | 45 + .../lib/isccfg/include/isccfg/version.h | 28 + contrib/bind-9.5.2/lib/isccfg/log.c | 52 + contrib/bind-9.5.2/lib/isccfg/namedconf.c | 2177 +++++ contrib/bind-9.5.2/lib/isccfg/parser.c | 2405 +++++ contrib/bind-9.5.2/lib/isccfg/version.c | 29 + contrib/bind-9.5.2/lib/lwres/api | 3 + contrib/bind-9.5.2/lib/lwres/assert_p.h | 35 + contrib/bind-9.5.2/lib/lwres/context.c | 492 + contrib/bind-9.5.2/lib/lwres/context_p.h | 67 + contrib/bind-9.5.2/lib/lwres/gai_strerror.c | 83 + contrib/bind-9.5.2/lib/lwres/getaddrinfo.c | 808 ++ contrib/bind-9.5.2/lib/lwres/gethost.c | 362 + contrib/bind-9.5.2/lib/lwres/getipnode.c | 1148 +++ contrib/bind-9.5.2/lib/lwres/getnameinfo.c | 346 + contrib/bind-9.5.2/lib/lwres/getrrset.c | 288 + contrib/bind-9.5.2/lib/lwres/herror.c | 122 + .../lib/lwres/include/lwres/context.h | 136 + .../bind-9.5.2/lib/lwres/include/lwres/int.h | 34 + .../bind-9.5.2/lib/lwres/include/lwres/ipv6.h | 124 + .../bind-9.5.2/lib/lwres/include/lwres/lang.h | 33 + .../bind-9.5.2/lib/lwres/include/lwres/list.h | 121 + .../lib/lwres/include/lwres/lwbuffer.h | 406 + .../lib/lwres/include/lwres/lwpacket.h | 159 + .../lib/lwres/include/lwres/lwres.h | 579 ++ .../lib/lwres/include/lwres/netdb.h.in | 520 + .../lib/lwres/include/lwres/platform.h.in | 120 + .../lib/lwres/include/lwres/result.h | 42 + .../lib/lwres/include/lwres/stdlib.h | 40 + .../lib/lwres/include/lwres/version.h | 28 + contrib/bind-9.5.2/lib/lwres/lwbuffer.c | 361 + contrib/bind-9.5.2/lib/lwres/lwconfig.c | 728 ++ contrib/bind-9.5.2/lib/lwres/lwinetaton.c | 205 + contrib/bind-9.5.2/lib/lwres/lwinetntop.c | 197 + contrib/bind-9.5.2/lib/lwres/lwinetpton.c | 209 + contrib/bind-9.5.2/lib/lwres/lwpacket.c | 129 + contrib/bind-9.5.2/lib/lwres/lwres_gabn.c | 505 + contrib/bind-9.5.2/lib/lwres/lwres_gnba.c | 415 + contrib/bind-9.5.2/lib/lwres/lwres_grbn.c | 426 + contrib/bind-9.5.2/lib/lwres/lwres_noop.c | 342 + contrib/bind-9.5.2/lib/lwres/lwresutil.c | 576 ++ contrib/bind-9.5.2/lib/lwres/man/lwres.3 | 165 + contrib/bind-9.5.2/lib/lwres/man/lwres.html | 218 + .../bind-9.5.2/lib/lwres/man/lwres_buffer.3 | 233 + .../lib/lwres/man/lwres_buffer.html | 455 + .../bind-9.5.2/lib/lwres/man/lwres_config.3 | 106 + .../lib/lwres/man/lwres_config.html | 156 + .../bind-9.5.2/lib/lwres/man/lwres_context.3 | 170 + .../lib/lwres/man/lwres_context.html | 295 + contrib/bind-9.5.2/lib/lwres/man/lwres_gabn.3 | 195 + .../bind-9.5.2/lib/lwres/man/lwres_gabn.html | 324 + .../lib/lwres/man/lwres_gai_strerror.3 | 129 + .../lib/lwres/man/lwres_gai_strerror.html | 124 + .../lib/lwres/man/lwres_getaddrinfo.3 | 246 + .../lib/lwres/man/lwres_getaddrinfo.html | 322 + .../lib/lwres/man/lwres_gethostent.3 | 315 + .../lib/lwres/man/lwres_gethostent.html | 466 + .../lib/lwres/man/lwres_getipnode.3 | 206 + .../lib/lwres/man/lwres_getipnode.html | 279 + .../lib/lwres/man/lwres_getnameinfo.3 | 117 + .../lib/lwres/man/lwres_getnameinfo.html | 176 + .../lib/lwres/man/lwres_getrrsetbyname.3 | 164 + .../lib/lwres/man/lwres_getrrsetbyname.html | 192 + contrib/bind-9.5.2/lib/lwres/man/lwres_gnba.3 | 183 + .../bind-9.5.2/lib/lwres/man/lwres_gnba.html | 316 + .../lib/lwres/man/lwres_hstrerror.3 | 99 + .../lib/lwres/man/lwres_hstrerror.html | 104 + .../bind-9.5.2/lib/lwres/man/lwres_inetntop.3 | 77 + .../lib/lwres/man/lwres_inetntop.html | 103 + contrib/bind-9.5.2/lib/lwres/man/lwres_noop.3 | 183 + .../bind-9.5.2/lib/lwres/man/lwres_noop.html | 317 + .../bind-9.5.2/lib/lwres/man/lwres_packet.3 | 170 + .../lib/lwres/man/lwres_packet.html | 235 + .../bind-9.5.2/lib/lwres/man/lwres_resutil.3 | 170 + .../lib/lwres/man/lwres_resutil.html | 258 + contrib/bind-9.5.2/lib/lwres/print.c | 560 ++ contrib/bind-9.5.2/lib/lwres/print_p.h | 86 + contrib/bind-9.5.2/lib/lwres/strtoul.c | 135 + .../lib/lwres/unix/include/lwres/net.h | 135 + contrib/bind-9.5.2/lib/lwres/version.c | 28 + contrib/bind-9.5.2/version | 10 + 879 files changed, 334823 insertions(+) create mode 100644 contrib/bind-9.5.2/CHANGES create mode 100644 contrib/bind-9.5.2/COPYRIGHT create mode 100644 contrib/bind-9.5.2/FAQ create mode 100644 contrib/bind-9.5.2/README create mode 100644 contrib/bind-9.5.2/README.DELETED create mode 100644 contrib/bind-9.5.2/README.DRAGONFLY create mode 100644 contrib/bind-9.5.2/README.idnkit create mode 100644 contrib/bind-9.5.2/bin/check/check-tool.c create mode 100644 contrib/bind-9.5.2/bin/check/check-tool.h create mode 100644 contrib/bind-9.5.2/bin/check/named-checkconf.8 create mode 100644 contrib/bind-9.5.2/bin/check/named-checkconf.c create mode 100644 contrib/bind-9.5.2/bin/check/named-checkconf.html create mode 100644 contrib/bind-9.5.2/bin/check/named-checkzone.8 create mode 100644 contrib/bind-9.5.2/bin/check/named-checkzone.c create mode 100644 contrib/bind-9.5.2/bin/check/named-checkzone.html create mode 100644 contrib/bind-9.5.2/bin/dig/dig.1 create mode 100644 contrib/bind-9.5.2/bin/dig/dig.c create mode 100644 contrib/bind-9.5.2/bin/dig/dig.html create mode 100644 contrib/bind-9.5.2/bin/dig/dighost.c create mode 100644 contrib/bind-9.5.2/bin/dig/host.1 create mode 100644 contrib/bind-9.5.2/bin/dig/host.c create mode 100644 contrib/bind-9.5.2/bin/dig/host.html create mode 100644 contrib/bind-9.5.2/bin/dig/include/dig/dig.h create mode 100644 contrib/bind-9.5.2/bin/dig/nslookup.1 create mode 100644 contrib/bind-9.5.2/bin/dig/nslookup.c create mode 100644 contrib/bind-9.5.2/bin/dig/nslookup.html create mode 100644 contrib/bind-9.5.2/bin/dnssec/dnssec-keygen.8 create mode 100644 contrib/bind-9.5.2/bin/dnssec/dnssec-keygen.c create mode 100644 contrib/bind-9.5.2/bin/dnssec/dnssec-keygen.html create mode 100644 contrib/bind-9.5.2/bin/dnssec/dnssec-signzone.8 create mode 100644 contrib/bind-9.5.2/bin/dnssec/dnssec-signzone.c create mode 100644 contrib/bind-9.5.2/bin/dnssec/dnssec-signzone.html create mode 100644 contrib/bind-9.5.2/bin/dnssec/dnssectool.c create mode 100644 contrib/bind-9.5.2/bin/dnssec/dnssectool.h create mode 100644 contrib/bind-9.5.2/bin/named/bind9.xsl create mode 100644 contrib/bind-9.5.2/bin/named/bind9.xsl.h create mode 100644 contrib/bind-9.5.2/bin/named/builtin.c create mode 100644 contrib/bind-9.5.2/bin/named/client.c create mode 100644 contrib/bind-9.5.2/bin/named/config.c create mode 100644 contrib/bind-9.5.2/bin/named/control.c create mode 100644 contrib/bind-9.5.2/bin/named/controlconf.c create mode 100755 contrib/bind-9.5.2/bin/named/convertxsl.pl create mode 100644 contrib/bind-9.5.2/bin/named/include/named/builtin.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/client.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/config.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/control.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/globals.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/interfacemgr.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/listenlist.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/log.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/logconf.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/lwaddr.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/lwdclient.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/lwresd.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/lwsearch.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/main.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/notify.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/ns_smf_globals.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/query.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/server.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/sortlist.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/statschannel.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/tkeyconf.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/tsigconf.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/types.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/update.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/xfrout.h create mode 100644 contrib/bind-9.5.2/bin/named/include/named/zoneconf.h create mode 100644 contrib/bind-9.5.2/bin/named/interfacemgr.c create mode 100644 contrib/bind-9.5.2/bin/named/listenlist.c create mode 100644 contrib/bind-9.5.2/bin/named/log.c create mode 100644 contrib/bind-9.5.2/bin/named/logconf.c create mode 100644 contrib/bind-9.5.2/bin/named/lwaddr.c create mode 100644 contrib/bind-9.5.2/bin/named/lwdclient.c create mode 100644 contrib/bind-9.5.2/bin/named/lwderror.c create mode 100644 contrib/bind-9.5.2/bin/named/lwdgabn.c create mode 100644 contrib/bind-9.5.2/bin/named/lwdgnba.c create mode 100644 contrib/bind-9.5.2/bin/named/lwdgrbn.c create mode 100644 contrib/bind-9.5.2/bin/named/lwdnoop.c create mode 100644 contrib/bind-9.5.2/bin/named/lwresd.8 create mode 100644 contrib/bind-9.5.2/bin/named/lwresd.c create mode 100644 contrib/bind-9.5.2/bin/named/lwresd.html create mode 100644 contrib/bind-9.5.2/bin/named/lwsearch.c create mode 100644 contrib/bind-9.5.2/bin/named/main.c create mode 100644 contrib/bind-9.5.2/bin/named/named.8 create mode 100644 contrib/bind-9.5.2/bin/named/named.conf.5 create mode 100644 contrib/bind-9.5.2/bin/named/named.conf.html create mode 100644 contrib/bind-9.5.2/bin/named/named.html create mode 100644 contrib/bind-9.5.2/bin/named/notify.c create mode 100644 contrib/bind-9.5.2/bin/named/query.c create mode 100644 contrib/bind-9.5.2/bin/named/server.c create mode 100644 contrib/bind-9.5.2/bin/named/sortlist.c create mode 100644 contrib/bind-9.5.2/bin/named/statschannel.c create mode 100644 contrib/bind-9.5.2/bin/named/tkeyconf.c create mode 100644 contrib/bind-9.5.2/bin/named/tsigconf.c create mode 100644 contrib/bind-9.5.2/bin/named/unix/include/named/os.h create mode 100644 contrib/bind-9.5.2/bin/named/unix/os.c create mode 100644 contrib/bind-9.5.2/bin/named/update.c create mode 100644 contrib/bind-9.5.2/bin/named/xfrout.c create mode 100644 contrib/bind-9.5.2/bin/named/zoneconf.c create mode 100644 contrib/bind-9.5.2/bin/nsupdate/nsupdate.1 create mode 100644 contrib/bind-9.5.2/bin/nsupdate/nsupdate.c create mode 100644 contrib/bind-9.5.2/bin/nsupdate/nsupdate.html create mode 100644 contrib/bind-9.5.2/bin/rndc/include/rndc/os.h create mode 100644 contrib/bind-9.5.2/bin/rndc/rndc-confgen.8 create mode 100644 contrib/bind-9.5.2/bin/rndc/rndc-confgen.c create mode 100644 contrib/bind-9.5.2/bin/rndc/rndc-confgen.html create mode 100644 contrib/bind-9.5.2/bin/rndc/rndc.8 create mode 100644 contrib/bind-9.5.2/bin/rndc/rndc.c create mode 100644 contrib/bind-9.5.2/bin/rndc/rndc.conf create mode 100644 contrib/bind-9.5.2/bin/rndc/rndc.conf.5 create mode 100644 contrib/bind-9.5.2/bin/rndc/rndc.conf.html create mode 100644 contrib/bind-9.5.2/bin/rndc/rndc.html create mode 100644 contrib/bind-9.5.2/bin/rndc/unix/os.c create mode 100644 contrib/bind-9.5.2/bin/rndc/util.c create mode 100644 contrib/bind-9.5.2/bin/rndc/util.h create mode 100644 contrib/bind-9.5.2/bind.keys create mode 100644 contrib/bind-9.5.2/lib/bind/README create mode 100644 contrib/bind-9.5.2/lib/bind/api create mode 100644 contrib/bind-9.5.2/lib/bind/bsd/daemon.c create mode 100644 contrib/bind-9.5.2/lib/bind/bsd/ftruncate.c create mode 100644 contrib/bind-9.5.2/lib/bind/bsd/gettimeofday.c create mode 100644 contrib/bind-9.5.2/lib/bind/bsd/mktemp.c create mode 100644 contrib/bind-9.5.2/lib/bind/bsd/putenv.c create mode 100644 contrib/bind-9.5.2/lib/bind/bsd/readv.c create mode 100644 contrib/bind-9.5.2/lib/bind/bsd/setenv.c create mode 100644 contrib/bind-9.5.2/lib/bind/bsd/setitimer.c create mode 100644 contrib/bind-9.5.2/lib/bind/bsd/strcasecmp.c create mode 100644 contrib/bind-9.5.2/lib/bind/bsd/strdup.c create mode 100644 contrib/bind-9.5.2/lib/bind/bsd/strerror.c create mode 100644 contrib/bind-9.5.2/lib/bind/bsd/strpbrk.c create mode 100644 contrib/bind-9.5.2/lib/bind/bsd/strsep.c create mode 100644 contrib/bind-9.5.2/lib/bind/bsd/strtoul.c create mode 100644 contrib/bind-9.5.2/lib/bind/bsd/utimes.c create mode 100644 contrib/bind-9.5.2/lib/bind/bsd/writev.c create mode 100644 contrib/bind-9.5.2/lib/bind/config.h.in create mode 100644 contrib/bind-9.5.2/lib/bind/dst/dst_api.c create mode 100644 contrib/bind-9.5.2/lib/bind/dst/dst_internal.h create mode 100644 contrib/bind-9.5.2/lib/bind/dst/hmac_link.c create mode 100644 contrib/bind-9.5.2/lib/bind/dst/md5.h create mode 100644 contrib/bind-9.5.2/lib/bind/dst/md5_dgst.c create mode 100644 contrib/bind-9.5.2/lib/bind/dst/md5_locl.h create mode 100644 contrib/bind-9.5.2/lib/bind/dst/support.c create mode 100644 contrib/bind-9.5.2/lib/bind/include/arpa/inet.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/arpa/nameser.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/arpa/nameser_compat.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/fd_setsize.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/hesiod.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/irp.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/irs.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/isc/assertions.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/isc/ctl.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/isc/dst.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/isc/eventlib.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/isc/heap.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/isc/irpmarshall.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/isc/list.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/isc/logging.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/isc/memcluster.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/isc/misc.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/isc/platform.h.in create mode 100644 contrib/bind-9.5.2/lib/bind/include/isc/tree.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/netdb.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/netgroup.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/res_update.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/resolv.h create mode 100644 contrib/bind-9.5.2/lib/bind/include/resolv_mt.h create mode 100644 contrib/bind-9.5.2/lib/bind/inet/inet_addr.c create mode 100644 contrib/bind-9.5.2/lib/bind/inet/inet_cidr_ntop.c create mode 100644 contrib/bind-9.5.2/lib/bind/inet/inet_cidr_pton.c create mode 100644 contrib/bind-9.5.2/lib/bind/inet/inet_data.c create mode 100644 contrib/bind-9.5.2/lib/bind/inet/inet_lnaof.c create mode 100644 contrib/bind-9.5.2/lib/bind/inet/inet_makeaddr.c create mode 100644 contrib/bind-9.5.2/lib/bind/inet/inet_net_ntop.c create mode 100644 contrib/bind-9.5.2/lib/bind/inet/inet_net_pton.c create mode 100644 contrib/bind-9.5.2/lib/bind/inet/inet_neta.c create mode 100644 contrib/bind-9.5.2/lib/bind/inet/inet_netof.c create mode 100644 contrib/bind-9.5.2/lib/bind/inet/inet_network.c create mode 100644 contrib/bind-9.5.2/lib/bind/inet/inet_ntoa.c create mode 100644 contrib/bind-9.5.2/lib/bind/inet/inet_ntop.c create mode 100644 contrib/bind-9.5.2/lib/bind/inet/inet_pton.c create mode 100644 contrib/bind-9.5.2/lib/bind/inet/nsap_addr.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/dns.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/dns_gr.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/dns_ho.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/dns_nw.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/dns_p.h create mode 100644 contrib/bind-9.5.2/lib/bind/irs/dns_pr.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/dns_pw.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/dns_sv.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/gai_strerror.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/gen.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/gen_gr.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/gen_ho.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/gen_ng.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/gen_nw.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/gen_p.h create mode 100644 contrib/bind-9.5.2/lib/bind/irs/gen_pr.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/gen_pw.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/gen_sv.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/getaddrinfo.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/getgrent.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/getgrent_r.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/gethostent.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/gethostent_r.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/getnameinfo.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/getnetent.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/getnetent_r.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/getnetgrent.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/getnetgrent_r.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/getprotoent.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/getprotoent_r.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/getpwent.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/getpwent_r.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/getservent.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/getservent_r.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/hesiod.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/hesiod_p.h create mode 100644 contrib/bind-9.5.2/lib/bind/irs/irp.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/irp_gr.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/irp_ho.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/irp_ng.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/irp_nw.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/irp_p.h create mode 100644 contrib/bind-9.5.2/lib/bind/irs/irp_pr.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/irp_pw.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/irp_sv.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/irpmarshall.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/irs_data.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/irs_data.h create mode 100644 contrib/bind-9.5.2/lib/bind/irs/irs_p.h create mode 100644 contrib/bind-9.5.2/lib/bind/irs/lcl.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/lcl_gr.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/lcl_ho.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/lcl_ng.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/lcl_nw.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/lcl_p.h create mode 100644 contrib/bind-9.5.2/lib/bind/irs/lcl_pr.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/lcl_pw.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/lcl_sv.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/nis.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/nis_gr.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/nis_ho.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/nis_ng.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/nis_nw.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/nis_p.h create mode 100644 contrib/bind-9.5.2/lib/bind/irs/nis_pr.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/nis_pw.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/nis_sv.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/nul_ng.c create mode 100644 contrib/bind-9.5.2/lib/bind/irs/pathnames.h create mode 100644 contrib/bind-9.5.2/lib/bind/irs/util.c create mode 100644 contrib/bind-9.5.2/lib/bind/isc/assertions.c create mode 100644 contrib/bind-9.5.2/lib/bind/isc/assertions.mdoc create mode 100644 contrib/bind-9.5.2/lib/bind/isc/base64.c create mode 100644 contrib/bind-9.5.2/lib/bind/isc/bitncmp.c create mode 100644 contrib/bind-9.5.2/lib/bind/isc/bitncmp.mdoc create mode 100644 contrib/bind-9.5.2/lib/bind/isc/ctl_clnt.c create mode 100644 contrib/bind-9.5.2/lib/bind/isc/ctl_p.c create mode 100644 contrib/bind-9.5.2/lib/bind/isc/ctl_p.h create mode 100644 contrib/bind-9.5.2/lib/bind/isc/ctl_srvr.c create mode 100644 contrib/bind-9.5.2/lib/bind/isc/ev_connects.c create mode 100644 contrib/bind-9.5.2/lib/bind/isc/ev_files.c create mode 100644 contrib/bind-9.5.2/lib/bind/isc/ev_streams.c create mode 100644 contrib/bind-9.5.2/lib/bind/isc/ev_timers.c create mode 100644 contrib/bind-9.5.2/lib/bind/isc/ev_waits.c create mode 100644 contrib/bind-9.5.2/lib/bind/isc/eventlib.c create mode 100644 contrib/bind-9.5.2/lib/bind/isc/eventlib.mdoc create mode 100644 contrib/bind-9.5.2/lib/bind/isc/eventlib_p.h create mode 100644 contrib/bind-9.5.2/lib/bind/isc/heap.c create mode 100644 contrib/bind-9.5.2/lib/bind/isc/heap.mdoc create mode 100644 contrib/bind-9.5.2/lib/bind/isc/hex.c create mode 100644 contrib/bind-9.5.2/lib/bind/isc/logging.c create mode 100644 contrib/bind-9.5.2/lib/bind/isc/logging.mdoc create mode 100644 contrib/bind-9.5.2/lib/bind/isc/logging_p.h create mode 100644 contrib/bind-9.5.2/lib/bind/isc/memcluster.c create mode 100644 contrib/bind-9.5.2/lib/bind/isc/memcluster.mdoc create mode 100644 contrib/bind-9.5.2/lib/bind/isc/movefile.c create mode 100644 contrib/bind-9.5.2/lib/bind/isc/tree.c create mode 100644 contrib/bind-9.5.2/lib/bind/isc/tree.mdoc create mode 100644 contrib/bind-9.5.2/lib/bind/make/includes.in create mode 100644 contrib/bind-9.5.2/lib/bind/make/mkdep.in create mode 100644 contrib/bind-9.5.2/lib/bind/make/rules.in create mode 100755 contrib/bind-9.5.2/lib/bind/mkinstalldirs create mode 100644 contrib/bind-9.5.2/lib/bind/nameser/ns_date.c create mode 100644 contrib/bind-9.5.2/lib/bind/nameser/ns_name.c create mode 100644 contrib/bind-9.5.2/lib/bind/nameser/ns_netint.c create mode 100644 contrib/bind-9.5.2/lib/bind/nameser/ns_parse.c create mode 100644 contrib/bind-9.5.2/lib/bind/nameser/ns_print.c create mode 100644 contrib/bind-9.5.2/lib/bind/nameser/ns_samedomain.c create mode 100644 contrib/bind-9.5.2/lib/bind/nameser/ns_sign.c create mode 100644 contrib/bind-9.5.2/lib/bind/nameser/ns_ttl.c create mode 100644 contrib/bind-9.5.2/lib/bind/nameser/ns_verify.c create mode 100644 contrib/bind-9.5.2/lib/bind/port/freebsd/include/sys/bitypes.h create mode 100644 contrib/bind-9.5.2/lib/bind/port_after.h.in create mode 100644 contrib/bind-9.5.2/lib/bind/port_before.h.in create mode 100644 contrib/bind-9.5.2/lib/bind/resolv/herror.c create mode 100644 contrib/bind-9.5.2/lib/bind/resolv/mtctxres.c create mode 100644 contrib/bind-9.5.2/lib/bind/resolv/res_comp.c create mode 100644 contrib/bind-9.5.2/lib/bind/resolv/res_data.c create mode 100644 contrib/bind-9.5.2/lib/bind/resolv/res_debug.c create mode 100644 contrib/bind-9.5.2/lib/bind/resolv/res_debug.h create mode 100644 contrib/bind-9.5.2/lib/bind/resolv/res_findzonecut.c create mode 100644 contrib/bind-9.5.2/lib/bind/resolv/res_init.c create mode 100644 contrib/bind-9.5.2/lib/bind/resolv/res_mkquery.c create mode 100644 contrib/bind-9.5.2/lib/bind/resolv/res_mkupdate.c create mode 100644 contrib/bind-9.5.2/lib/bind/resolv/res_mkupdate.h create mode 100644 contrib/bind-9.5.2/lib/bind/resolv/res_private.h create mode 100644 contrib/bind-9.5.2/lib/bind/resolv/res_query.c create mode 100644 contrib/bind-9.5.2/lib/bind/resolv/res_send.c create mode 100644 contrib/bind-9.5.2/lib/bind/resolv/res_sendsigned.c create mode 100644 contrib/bind-9.5.2/lib/bind/resolv/res_update.c create mode 100644 contrib/bind-9.5.2/lib/bind9/api create mode 100644 contrib/bind-9.5.2/lib/bind9/check.c create mode 100644 contrib/bind-9.5.2/lib/bind9/getaddresses.c create mode 100644 contrib/bind-9.5.2/lib/bind9/include/bind9/check.h create mode 100644 contrib/bind-9.5.2/lib/bind9/include/bind9/getaddresses.h create mode 100644 contrib/bind-9.5.2/lib/bind9/include/bind9/version.h create mode 100644 contrib/bind-9.5.2/lib/bind9/version.c create mode 100644 contrib/bind-9.5.2/lib/dns/acache.c create mode 100644 contrib/bind-9.5.2/lib/dns/acl.c create mode 100644 contrib/bind-9.5.2/lib/dns/adb.c create mode 100644 contrib/bind-9.5.2/lib/dns/api create mode 100644 contrib/bind-9.5.2/lib/dns/byaddr.c create mode 100644 contrib/bind-9.5.2/lib/dns/cache.c create mode 100644 contrib/bind-9.5.2/lib/dns/callbacks.c create mode 100644 contrib/bind-9.5.2/lib/dns/compress.c create mode 100644 contrib/bind-9.5.2/lib/dns/db.c create mode 100644 contrib/bind-9.5.2/lib/dns/dbiterator.c create mode 100644 contrib/bind-9.5.2/lib/dns/dbtable.c create mode 100644 contrib/bind-9.5.2/lib/dns/diff.c create mode 100644 contrib/bind-9.5.2/lib/dns/dispatch.c create mode 100644 contrib/bind-9.5.2/lib/dns/dlz.c create mode 100644 contrib/bind-9.5.2/lib/dns/dnssec.c create mode 100644 contrib/bind-9.5.2/lib/dns/ds.c create mode 100644 contrib/bind-9.5.2/lib/dns/dst_api.c create mode 100644 contrib/bind-9.5.2/lib/dns/dst_internal.h create mode 100644 contrib/bind-9.5.2/lib/dns/dst_lib.c create mode 100644 contrib/bind-9.5.2/lib/dns/dst_openssl.h create mode 100644 contrib/bind-9.5.2/lib/dns/dst_parse.c create mode 100644 contrib/bind-9.5.2/lib/dns/dst_parse.h create mode 100644 contrib/bind-9.5.2/lib/dns/dst_result.c create mode 100644 contrib/bind-9.5.2/lib/dns/forward.c create mode 100644 contrib/bind-9.5.2/lib/dns/gen-unix.h create mode 100644 contrib/bind-9.5.2/lib/dns/gen-win32.h create mode 100644 contrib/bind-9.5.2/lib/dns/gen.c create mode 100644 contrib/bind-9.5.2/lib/dns/gssapi_link.c create mode 100644 contrib/bind-9.5.2/lib/dns/gssapictx.c create mode 100644 contrib/bind-9.5.2/lib/dns/hmac_link.c create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/acache.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/acl.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/adb.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/bit.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/byaddr.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/cache.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/callbacks.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/cert.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/compress.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/db.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/dbiterator.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/dbtable.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/diff.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/dispatch.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/dlz.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/dnssec.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/ds.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/events.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/fixedname.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/forward.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/iptable.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/journal.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/keyflags.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/keytable.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/keyvalues.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/lib.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/log.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/lookup.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/master.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/masterdump.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/message.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/name.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/ncache.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/nsec.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/opcode.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/order.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/peer.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/portlist.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/rbt.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/rcode.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/rdata.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/rdataclass.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/rdatalist.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/rdataset.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/rdatasetiter.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/rdataslab.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/rdatatype.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/request.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/resolver.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/result.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/rootns.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/sdb.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/sdlz.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/secalg.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/secproto.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/soa.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/ssu.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/stats.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/tcpmsg.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/time.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/timer.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/tkey.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/tsig.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/ttl.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/types.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/validator.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/version.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/view.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/xfrin.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/zone.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/zonekey.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dns/zt.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dst/dst.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dst/gssapi.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dst/lib.h create mode 100644 contrib/bind-9.5.2/lib/dns/include/dst/result.h create mode 100644 contrib/bind-9.5.2/lib/dns/iptable.c create mode 100644 contrib/bind-9.5.2/lib/dns/journal.c create mode 100644 contrib/bind-9.5.2/lib/dns/key.c create mode 100644 contrib/bind-9.5.2/lib/dns/keytable.c create mode 100644 contrib/bind-9.5.2/lib/dns/lib.c create mode 100644 contrib/bind-9.5.2/lib/dns/log.c create mode 100644 contrib/bind-9.5.2/lib/dns/lookup.c create mode 100644 contrib/bind-9.5.2/lib/dns/master.c create mode 100644 contrib/bind-9.5.2/lib/dns/masterdump.c create mode 100644 contrib/bind-9.5.2/lib/dns/message.c create mode 100644 contrib/bind-9.5.2/lib/dns/name.c create mode 100644 contrib/bind-9.5.2/lib/dns/ncache.c create mode 100644 contrib/bind-9.5.2/lib/dns/nsec.c create mode 100644 contrib/bind-9.5.2/lib/dns/openssl_link.c create mode 100644 contrib/bind-9.5.2/lib/dns/openssldh_link.c create mode 100644 contrib/bind-9.5.2/lib/dns/openssldsa_link.c create mode 100644 contrib/bind-9.5.2/lib/dns/opensslrsa_link.c create mode 100644 contrib/bind-9.5.2/lib/dns/order.c create mode 100644 contrib/bind-9.5.2/lib/dns/peer.c create mode 100644 contrib/bind-9.5.2/lib/dns/portlist.c create mode 100644 contrib/bind-9.5.2/lib/dns/rbt.c create mode 100644 contrib/bind-9.5.2/lib/dns/rbtdb.c create mode 100644 contrib/bind-9.5.2/lib/dns/rbtdb.h create mode 100644 contrib/bind-9.5.2/lib/dns/rbtdb64.c create mode 100644 contrib/bind-9.5.2/lib/dns/rbtdb64.h create mode 100644 contrib/bind-9.5.2/lib/dns/rcode.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/any_255/tsig_250.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/any_255/tsig_250.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/ch_3/a_1.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/ch_3/a_1.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/afsdb_18.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/afsdb_18.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/cert_37.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/cert_37.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/cname_5.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/cname_5.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/dlv_32769.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/dlv_32769.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/dname_39.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/dname_39.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/dnskey_48.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/dnskey_48.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/ds_43.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/ds_43.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/gpos_27.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/gpos_27.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/hinfo_13.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/hinfo_13.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/ipseckey_45.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/ipseckey_45.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/isdn_20.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/isdn_20.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/key_25.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/key_25.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/loc_29.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/loc_29.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/mb_7.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/mb_7.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/md_3.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/md_3.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/mf_4.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/mf_4.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/mg_8.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/mg_8.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/minfo_14.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/minfo_14.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/mr_9.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/mr_9.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/mx_15.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/mx_15.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/ns_2.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/ns_2.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/nsec_47.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/nsec_47.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/null_10.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/null_10.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/nxt_30.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/nxt_30.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/opt_41.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/opt_41.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/proforma.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/proforma.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/ptr_12.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/ptr_12.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/rp_17.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/rp_17.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/rrsig_46.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/rrsig_46.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/rt_21.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/rt_21.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/sig_24.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/sig_24.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/soa_6.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/soa_6.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/spf_99.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/spf_99.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/sshfp_44.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/sshfp_44.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/tkey_249.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/tkey_249.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/txt_16.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/txt_16.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/unspec_103.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/unspec_103.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/x25_19.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/generic/x25_19.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/hs_4/a_1.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/hs_4/a_1.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/a6_38.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/a6_38.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/a_1.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/a_1.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/aaaa_28.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/aaaa_28.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/apl_42.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/apl_42.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/dhcid_49.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/dhcid_49.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/kx_36.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/kx_36.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/naptr_35.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/naptr_35.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/nsap-ptr_23.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/nsap-ptr_23.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/nsap_22.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/nsap_22.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/px_26.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/px_26.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/srv_33.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/srv_33.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/wks_11.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/in_1/wks_11.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/rdatastructpre.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdata/rdatastructsuf.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdatalist.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdatalist_p.h create mode 100644 contrib/bind-9.5.2/lib/dns/rdataset.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdatasetiter.c create mode 100644 contrib/bind-9.5.2/lib/dns/rdataslab.c create mode 100644 contrib/bind-9.5.2/lib/dns/request.c create mode 100644 contrib/bind-9.5.2/lib/dns/resolver.c create mode 100644 contrib/bind-9.5.2/lib/dns/result.c create mode 100644 contrib/bind-9.5.2/lib/dns/rootns.c create mode 100644 contrib/bind-9.5.2/lib/dns/sdb.c create mode 100644 contrib/bind-9.5.2/lib/dns/sdlz.c create mode 100644 contrib/bind-9.5.2/lib/dns/soa.c create mode 100644 contrib/bind-9.5.2/lib/dns/spnego.asn1 create mode 100644 contrib/bind-9.5.2/lib/dns/spnego.c create mode 100644 contrib/bind-9.5.2/lib/dns/spnego.h create mode 100644 contrib/bind-9.5.2/lib/dns/spnego_asn1.c create mode 100644 contrib/bind-9.5.2/lib/dns/spnego_asn1.pl create mode 100644 contrib/bind-9.5.2/lib/dns/ssu.c create mode 100644 contrib/bind-9.5.2/lib/dns/stats.c create mode 100644 contrib/bind-9.5.2/lib/dns/tcpmsg.c create mode 100644 contrib/bind-9.5.2/lib/dns/time.c create mode 100644 contrib/bind-9.5.2/lib/dns/timer.c create mode 100644 contrib/bind-9.5.2/lib/dns/tkey.c create mode 100644 contrib/bind-9.5.2/lib/dns/tsig.c create mode 100644 contrib/bind-9.5.2/lib/dns/ttl.c create mode 100644 contrib/bind-9.5.2/lib/dns/validator.c create mode 100644 contrib/bind-9.5.2/lib/dns/version.c create mode 100644 contrib/bind-9.5.2/lib/dns/view.c create mode 100644 contrib/bind-9.5.2/lib/dns/xfrin.c create mode 100644 contrib/bind-9.5.2/lib/dns/zone.c create mode 100644 contrib/bind-9.5.2/lib/dns/zonekey.c create mode 100644 contrib/bind-9.5.2/lib/dns/zt.c create mode 100644 contrib/bind-9.5.2/lib/isc/api create mode 100644 contrib/bind-9.5.2/lib/isc/assertions.c create mode 100644 contrib/bind-9.5.2/lib/isc/base64.c create mode 100644 contrib/bind-9.5.2/lib/isc/bitstring.c create mode 100644 contrib/bind-9.5.2/lib/isc/buffer.c create mode 100644 contrib/bind-9.5.2/lib/isc/bufferlist.c create mode 100644 contrib/bind-9.5.2/lib/isc/commandline.c create mode 100644 contrib/bind-9.5.2/lib/isc/entropy.c create mode 100644 contrib/bind-9.5.2/lib/isc/error.c create mode 100644 contrib/bind-9.5.2/lib/isc/event.c create mode 100644 contrib/bind-9.5.2/lib/isc/fsaccess.c create mode 100644 contrib/bind-9.5.2/lib/isc/hash.c create mode 100644 contrib/bind-9.5.2/lib/isc/heap.c create mode 100644 contrib/bind-9.5.2/lib/isc/hex.c create mode 100644 contrib/bind-9.5.2/lib/isc/hmacmd5.c create mode 100644 contrib/bind-9.5.2/lib/isc/hmacsha.c create mode 100644 contrib/bind-9.5.2/lib/isc/httpd.c create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/app.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/assertions.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/base64.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/bitstring.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/boolean.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/buffer.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/bufferlist.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/commandline.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/entropy.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/error.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/event.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/eventclass.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/file.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/formatcheck.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/fsaccess.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/hash.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/heap.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/hex.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/hmacmd5.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/hmacsha.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/httpd.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/interfaceiter.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/ipv6.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/lang.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/lex.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/lfsr.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/lib.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/list.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/log.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/magic.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/md5.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/mem.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/msgcat.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/msgs.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/mutexblock.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/netaddr.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/netscope.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/ondestroy.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/os.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/parseint.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/platform.h.in create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/portset.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/print.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/quota.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/radix.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/random.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/ratelimiter.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/refcount.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/region.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/resource.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/result.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/resultclass.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/rwlock.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/serial.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/sha1.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/sha2.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/sockaddr.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/socket.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/stats.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/stdio.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/stdlib.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/string.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/symtab.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/task.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/taskpool.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/timer.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/types.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/util.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/version.h create mode 100644 contrib/bind-9.5.2/lib/isc/include/isc/xml.h create mode 100644 contrib/bind-9.5.2/lib/isc/inet_aton.c create mode 100644 contrib/bind-9.5.2/lib/isc/inet_ntop.c create mode 100644 contrib/bind-9.5.2/lib/isc/inet_pton.c create mode 100644 contrib/bind-9.5.2/lib/isc/lex.c create mode 100644 contrib/bind-9.5.2/lib/isc/lfsr.c create mode 100644 contrib/bind-9.5.2/lib/isc/lib.c create mode 100644 contrib/bind-9.5.2/lib/isc/log.c create mode 100644 contrib/bind-9.5.2/lib/isc/md5.c create mode 100644 contrib/bind-9.5.2/lib/isc/mem.c create mode 100644 contrib/bind-9.5.2/lib/isc/mutexblock.c create mode 100644 contrib/bind-9.5.2/lib/isc/netaddr.c create mode 100644 contrib/bind-9.5.2/lib/isc/netscope.c create mode 100644 contrib/bind-9.5.2/lib/isc/nls/msgcat.c create mode 100644 contrib/bind-9.5.2/lib/isc/noatomic/include/isc/atomic.h create mode 100644 contrib/bind-9.5.2/lib/isc/nothreads/condition.c create mode 100644 contrib/bind-9.5.2/lib/isc/nothreads/include/isc/condition.h create mode 100644 contrib/bind-9.5.2/lib/isc/nothreads/include/isc/mutex.h create mode 100644 contrib/bind-9.5.2/lib/isc/nothreads/include/isc/once.h create mode 100644 contrib/bind-9.5.2/lib/isc/nothreads/include/isc/thread.h create mode 100644 contrib/bind-9.5.2/lib/isc/nothreads/mutex.c create mode 100644 contrib/bind-9.5.2/lib/isc/nothreads/thread.c create mode 100644 contrib/bind-9.5.2/lib/isc/ondestroy.c create mode 100644 contrib/bind-9.5.2/lib/isc/parseint.c create mode 100644 contrib/bind-9.5.2/lib/isc/portset.c create mode 100644 contrib/bind-9.5.2/lib/isc/print.c create mode 100644 contrib/bind-9.5.2/lib/isc/pthreads/condition.c create mode 100644 contrib/bind-9.5.2/lib/isc/pthreads/include/isc/condition.h create mode 100644 contrib/bind-9.5.2/lib/isc/pthreads/include/isc/mutex.h create mode 100644 contrib/bind-9.5.2/lib/isc/pthreads/include/isc/once.h create mode 100644 contrib/bind-9.5.2/lib/isc/pthreads/include/isc/thread.h create mode 100644 contrib/bind-9.5.2/lib/isc/pthreads/mutex.c create mode 100644 contrib/bind-9.5.2/lib/isc/pthreads/thread.c create mode 100644 contrib/bind-9.5.2/lib/isc/quota.c create mode 100644 contrib/bind-9.5.2/lib/isc/radix.c create mode 100644 contrib/bind-9.5.2/lib/isc/random.c create mode 100644 contrib/bind-9.5.2/lib/isc/ratelimiter.c create mode 100644 contrib/bind-9.5.2/lib/isc/refcount.c create mode 100644 contrib/bind-9.5.2/lib/isc/region.c create mode 100644 contrib/bind-9.5.2/lib/isc/result.c create mode 100644 contrib/bind-9.5.2/lib/isc/rwlock.c create mode 100644 contrib/bind-9.5.2/lib/isc/serial.c create mode 100644 contrib/bind-9.5.2/lib/isc/sha1.c create mode 100644 contrib/bind-9.5.2/lib/isc/sha2.c create mode 100644 contrib/bind-9.5.2/lib/isc/sockaddr.c create mode 100644 contrib/bind-9.5.2/lib/isc/stats.c create mode 100644 contrib/bind-9.5.2/lib/isc/string.c create mode 100644 contrib/bind-9.5.2/lib/isc/strtoul.c create mode 100644 contrib/bind-9.5.2/lib/isc/symtab.c create mode 100644 contrib/bind-9.5.2/lib/isc/task.c create mode 100644 contrib/bind-9.5.2/lib/isc/task_p.h create mode 100644 contrib/bind-9.5.2/lib/isc/taskpool.c create mode 100644 contrib/bind-9.5.2/lib/isc/timer.c create mode 100644 contrib/bind-9.5.2/lib/isc/timer_p.h create mode 100644 contrib/bind-9.5.2/lib/isc/unix/app.c create mode 100644 contrib/bind-9.5.2/lib/isc/unix/dir.c create mode 100644 contrib/bind-9.5.2/lib/isc/unix/entropy.c create mode 100644 contrib/bind-9.5.2/lib/isc/unix/errno2result.c create mode 100644 contrib/bind-9.5.2/lib/isc/unix/errno2result.h create mode 100644 contrib/bind-9.5.2/lib/isc/unix/file.c create mode 100644 contrib/bind-9.5.2/lib/isc/unix/fsaccess.c create mode 100644 contrib/bind-9.5.2/lib/isc/unix/ifiter_getifaddrs.c create mode 100644 contrib/bind-9.5.2/lib/isc/unix/ifiter_ioctl.c create mode 100644 contrib/bind-9.5.2/lib/isc/unix/ifiter_sysctl.c create mode 100644 contrib/bind-9.5.2/lib/isc/unix/include/isc/dir.h create mode 100644 contrib/bind-9.5.2/lib/isc/unix/include/isc/int.h create mode 100644 contrib/bind-9.5.2/lib/isc/unix/include/isc/keyboard.h create mode 100644 contrib/bind-9.5.2/lib/isc/unix/include/isc/net.h create mode 100644 contrib/bind-9.5.2/lib/isc/unix/include/isc/netdb.h create mode 100644 contrib/bind-9.5.2/lib/isc/unix/include/isc/offset.h create mode 100644 contrib/bind-9.5.2/lib/isc/unix/include/isc/stat.h create mode 100644 contrib/bind-9.5.2/lib/isc/unix/include/isc/stdtime.h create mode 100644 contrib/bind-9.5.2/lib/isc/unix/include/isc/strerror.h create mode 100644 contrib/bind-9.5.2/lib/isc/unix/include/isc/syslog.h create mode 100644 contrib/bind-9.5.2/lib/isc/unix/include/isc/time.h create mode 100644 contrib/bind-9.5.2/lib/isc/unix/interfaceiter.c create mode 100644 contrib/bind-9.5.2/lib/isc/unix/ipv6.c create mode 100644 contrib/bind-9.5.2/lib/isc/unix/keyboard.c create mode 100644 contrib/bind-9.5.2/lib/isc/unix/net.c create mode 100644 contrib/bind-9.5.2/lib/isc/unix/os.c create mode 100644 contrib/bind-9.5.2/lib/isc/unix/resource.c create mode 100644 contrib/bind-9.5.2/lib/isc/unix/socket.c create mode 100644 contrib/bind-9.5.2/lib/isc/unix/socket_p.h create mode 100644 contrib/bind-9.5.2/lib/isc/unix/stdio.c create mode 100644 contrib/bind-9.5.2/lib/isc/unix/stdtime.c create mode 100644 contrib/bind-9.5.2/lib/isc/unix/strerror.c create mode 100644 contrib/bind-9.5.2/lib/isc/unix/syslog.c create mode 100644 contrib/bind-9.5.2/lib/isc/unix/time.c create mode 100644 contrib/bind-9.5.2/lib/isc/version.c create mode 100644 contrib/bind-9.5.2/lib/isc/x86_32/include/isc/atomic.h create mode 100644 contrib/bind-9.5.2/lib/isc/x86_64/include/isc/atomic.h create mode 100644 contrib/bind-9.5.2/lib/isccc/alist.c create mode 100644 contrib/bind-9.5.2/lib/isccc/api create mode 100644 contrib/bind-9.5.2/lib/isccc/base64.c create mode 100644 contrib/bind-9.5.2/lib/isccc/cc.c create mode 100644 contrib/bind-9.5.2/lib/isccc/ccmsg.c create mode 100644 contrib/bind-9.5.2/lib/isccc/include/isccc/alist.h create mode 100644 contrib/bind-9.5.2/lib/isccc/include/isccc/base64.h create mode 100644 contrib/bind-9.5.2/lib/isccc/include/isccc/cc.h create mode 100644 contrib/bind-9.5.2/lib/isccc/include/isccc/ccmsg.h create mode 100644 contrib/bind-9.5.2/lib/isccc/include/isccc/events.h create mode 100644 contrib/bind-9.5.2/lib/isccc/include/isccc/lib.h create mode 100644 contrib/bind-9.5.2/lib/isccc/include/isccc/result.h create mode 100644 contrib/bind-9.5.2/lib/isccc/include/isccc/sexpr.h create mode 100644 contrib/bind-9.5.2/lib/isccc/include/isccc/symtab.h create mode 100644 contrib/bind-9.5.2/lib/isccc/include/isccc/symtype.h create mode 100644 contrib/bind-9.5.2/lib/isccc/include/isccc/types.h create mode 100644 contrib/bind-9.5.2/lib/isccc/include/isccc/util.h create mode 100644 contrib/bind-9.5.2/lib/isccc/include/isccc/version.h create mode 100644 contrib/bind-9.5.2/lib/isccc/lib.c create mode 100644 contrib/bind-9.5.2/lib/isccc/result.c create mode 100644 contrib/bind-9.5.2/lib/isccc/sexpr.c create mode 100644 contrib/bind-9.5.2/lib/isccc/symtab.c create mode 100644 contrib/bind-9.5.2/lib/isccc/version.c create mode 100644 contrib/bind-9.5.2/lib/isccfg/aclconf.c create mode 100644 contrib/bind-9.5.2/lib/isccfg/api create mode 100644 contrib/bind-9.5.2/lib/isccfg/include/isccfg/aclconf.h create mode 100644 contrib/bind-9.5.2/lib/isccfg/include/isccfg/cfg.h create mode 100644 contrib/bind-9.5.2/lib/isccfg/include/isccfg/grammar.h create mode 100644 contrib/bind-9.5.2/lib/isccfg/include/isccfg/log.h create mode 100644 contrib/bind-9.5.2/lib/isccfg/include/isccfg/namedconf.h create mode 100644 contrib/bind-9.5.2/lib/isccfg/include/isccfg/version.h create mode 100644 contrib/bind-9.5.2/lib/isccfg/log.c create mode 100644 contrib/bind-9.5.2/lib/isccfg/namedconf.c create mode 100644 contrib/bind-9.5.2/lib/isccfg/parser.c create mode 100644 contrib/bind-9.5.2/lib/isccfg/version.c create mode 100644 contrib/bind-9.5.2/lib/lwres/api create mode 100644 contrib/bind-9.5.2/lib/lwres/assert_p.h create mode 100644 contrib/bind-9.5.2/lib/lwres/context.c create mode 100644 contrib/bind-9.5.2/lib/lwres/context_p.h create mode 100644 contrib/bind-9.5.2/lib/lwres/gai_strerror.c create mode 100644 contrib/bind-9.5.2/lib/lwres/getaddrinfo.c create mode 100644 contrib/bind-9.5.2/lib/lwres/gethost.c create mode 100644 contrib/bind-9.5.2/lib/lwres/getipnode.c create mode 100644 contrib/bind-9.5.2/lib/lwres/getnameinfo.c create mode 100644 contrib/bind-9.5.2/lib/lwres/getrrset.c create mode 100644 contrib/bind-9.5.2/lib/lwres/herror.c create mode 100644 contrib/bind-9.5.2/lib/lwres/include/lwres/context.h create mode 100644 contrib/bind-9.5.2/lib/lwres/include/lwres/int.h create mode 100644 contrib/bind-9.5.2/lib/lwres/include/lwres/ipv6.h create mode 100644 contrib/bind-9.5.2/lib/lwres/include/lwres/lang.h create mode 100644 contrib/bind-9.5.2/lib/lwres/include/lwres/list.h create mode 100644 contrib/bind-9.5.2/lib/lwres/include/lwres/lwbuffer.h create mode 100644 contrib/bind-9.5.2/lib/lwres/include/lwres/lwpacket.h create mode 100644 contrib/bind-9.5.2/lib/lwres/include/lwres/lwres.h create mode 100644 contrib/bind-9.5.2/lib/lwres/include/lwres/netdb.h.in create mode 100644 contrib/bind-9.5.2/lib/lwres/include/lwres/platform.h.in create mode 100644 contrib/bind-9.5.2/lib/lwres/include/lwres/result.h create mode 100644 contrib/bind-9.5.2/lib/lwres/include/lwres/stdlib.h create mode 100644 contrib/bind-9.5.2/lib/lwres/include/lwres/version.h create mode 100644 contrib/bind-9.5.2/lib/lwres/lwbuffer.c create mode 100644 contrib/bind-9.5.2/lib/lwres/lwconfig.c create mode 100644 contrib/bind-9.5.2/lib/lwres/lwinetaton.c create mode 100644 contrib/bind-9.5.2/lib/lwres/lwinetntop.c create mode 100644 contrib/bind-9.5.2/lib/lwres/lwinetpton.c create mode 100644 contrib/bind-9.5.2/lib/lwres/lwpacket.c create mode 100644 contrib/bind-9.5.2/lib/lwres/lwres_gabn.c create mode 100644 contrib/bind-9.5.2/lib/lwres/lwres_gnba.c create mode 100644 contrib/bind-9.5.2/lib/lwres/lwres_grbn.c create mode 100644 contrib/bind-9.5.2/lib/lwres/lwres_noop.c create mode 100644 contrib/bind-9.5.2/lib/lwres/lwresutil.c create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres.3 create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres.html create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_buffer.3 create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_buffer.html create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_config.3 create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_config.html create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_context.3 create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_context.html create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_gabn.3 create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_gabn.html create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_gai_strerror.3 create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_gai_strerror.html create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_getaddrinfo.3 create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_getaddrinfo.html create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_gethostent.3 create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_gethostent.html create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_getipnode.3 create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_getipnode.html create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_getnameinfo.3 create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_getnameinfo.html create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_getrrsetbyname.3 create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_getrrsetbyname.html create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_gnba.3 create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_gnba.html create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_hstrerror.3 create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_hstrerror.html create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_inetntop.3 create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_inetntop.html create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_noop.3 create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_noop.html create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_packet.3 create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_packet.html create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_resutil.3 create mode 100644 contrib/bind-9.5.2/lib/lwres/man/lwres_resutil.html create mode 100644 contrib/bind-9.5.2/lib/lwres/print.c create mode 100644 contrib/bind-9.5.2/lib/lwres/print_p.h create mode 100644 contrib/bind-9.5.2/lib/lwres/strtoul.c create mode 100644 contrib/bind-9.5.2/lib/lwres/unix/include/lwres/net.h create mode 100644 contrib/bind-9.5.2/lib/lwres/version.c create mode 100644 contrib/bind-9.5.2/version diff --git a/contrib/bind-9.5.2/CHANGES b/contrib/bind-9.5.2/CHANGES new file mode 100644 index 0000000000..ffe99852ff --- /dev/null +++ b/contrib/bind-9.5.2/CHANGES @@ -0,0 +1,8182 @@ + + --- 9.5.2 released --- + +2681. [bug] IPSECKEY RR of gateway type 3 was not correctly + decoded. [RT #20269] + +2678. [func] Treat DS queries as if "minimal-response yes;" + was set. [RT #20258] + +2427. [func] Treat DNSKEY queries as if "minimal-response yes;" + was set. [RT #18528] + + --- 9.5.2rc1 released --- + +2672. [bug] Don't enable searching in 'host' when doing reverse + lookups. [RT #20218] + +2670. [bug] Unexpected connect failures failed to log enough + information to be useful. [RT #20205] + +2663. [func] win32: allow named to run as a service using + "NT AUTHORITY\LocalService" as the account. [RT #19977] + +2656. [func] win32: add a "tools only" check box to the installer + which causes it to only install dig, host, nslookup, + nsupdate and relevent dlls. [RT #19998] + +2655. [doc] Document that key-directory does not affect + rndc.key. [RT #20155] + + --- 9.5.2b1 released --- + +2649. [bug] Set the domain for forward only zones. [RT #19944] + +2648. [port] win32: isc_time_seconds() was broken. [RT #19900] + +2646. [bug] Incorrect cleanup on error in socket.c. [RT #19987] + +2645. [port] "gcc -m32" didn't work on amd64 and x86_64 platforms + which default to 64 bits. [RT #19927] + +2642. [bug] nsupdate could dump core on solaris when reading + improperly formatted key files. [RT #20015] + +2640. [security] A specially crafted update packet will cause named + to exit. [RT #20000] + +2637. [func] Rationalize dnssec-signzone's signwithkey() calling. + [RT #19959] + +2635. [bug] isc_inet_ntop() incorrectly handled 0.0/16 addresses. + [RT #19716] + +2633. [bug] Handle 15 bit rand() functions. [RT #19783] + +2632. [func] util/kit.sh: warn if documentation appears to be out of + date. [RT #19922] + +2623. [bug] Named started seaches for DS non-optimally. [RT #19915] + +2621. [doc] Made copyright boilterplate consistent. [RT #19833] + +2920. [bug] Delay thawing the zone until the reload of it has + completed successfully. [RT #19750] + +2618. [bug] The sdb and sdlz db_interator_seek() methods could + loop infinitely. [RT #19847] + +2617. [bug] ifconfig.sh failed to emit an error message when + run from the wrong location. [RT #19375] + +2616. [bug] 'host' used the nameservers from resolv.conf even + when a explicit nameserver was specified. [RT #19852] + +2615. [bug] "__attribute__((unused))" was in the wrong place + for ia64 gcc builds. [RT #19854] + +2614. [port] win32: 'named -v' should automatically be executed + in the foreground. [RT #19844] + +2610. [port] sunos: Change #2363 was not complete. [RT #19796] + +2606. [bug] "delegation-only" was not being accepted in + delegation-only type zones. [RT #19717] + +2605. [bug] Accept DS responses from delegation only zones. + [RT # 19296] + +2603. [port] win32: handle .exe extension of named-checkzone and + named-comilezone argv[0] names under windows. + [RT #19767] + +2602. [port] win32: fix debugging command line build of libisccfg. + [RT #19767] + +2599. [bug] Address rapid memory growth when validation fails. + [RT #19654] + +2596. [bug] Stale tree nodes of cache/dynamic rbtdb could stay + long, leading to inefficient memory usage or rejecting + newer cache entries in the worst case. [RT #19563] + +2595. [bug] Fix unknown extended rcodes in dig. [RT #19625] + +2592. [bug] Treat "any" as a type in nsupdate. [RT #19455] + +2591. [bug] named could die when processing a update in + removed_orphaned_ds(). [RT #19507] + +2589. [bug] dns_db_unregister() failed to clear '*dbimp'. + [RT #19626] + +2586. [bug] Missing cleanup of SIG rdataset in searching a DLZ DB + or SDB. [RT #19577] + +2585. [bug] Uninitialized socket name could be referenced via a + statistics channel, triggering an assertion failure in + XML rendering. [RT #19427] + +2584. [bug] alpha: gcc optimization could break atomic operations. + [RT #19227] + +2583. [port] netbsd: provide a control to not add the compile + date to the version string, -DNO_VERSION_DATE. + +2582. [bug] Don't emit warning log message when we attempt to + remove non-existant journal. [RT #19516] + +2581. [contrib] dlz/mysql set MYSQL_OPT_RECONNECT option on connection. + Requires MySQL 5.0.19 or later. [RT #19084] + +2580. [bug] UpdateRej statistics counter could be incremented twice + for one rejection. [RT #19476] + +2579. [bug] DNSSEC lookaside validation failed to handle unknown + algorithms. [RT #19479] + +2577. [doc] Clarified some statistics counters. [RT #19454] + +2573. [bug] Replacing a non-CNAME record with a CNAME record in a + single transaction in a signed zone failed. [RT #19397] + +2568. [bug] Report when the write to indicate a otherwise + successful start fails. [RT #19360] + +2567. [bug] dst__privstruct_writefile() could miss write errors. + write_public_key() could miss write errors. + [RT #19360] + +2564. [bug] Only take EDNS fallback steps when processing timeouts. + [RT #19405] + +2563. [bug] Dig could leak a socket causing it to wait forever + to exit. [RT #19359] + +2562. [doc] ARM: miscellaneous improvements, reorganization, + and some new content. + +2561. [doc] Add isc-config.sh(1) man page. [RT #16378] + +2560. [bug] Add #include to iptable.c. [RT #18258] + +2557. [cleanup] PCI compliance: + * new libisc log module file + * isc_dir_chroot() now also changes the working + directory to "/". + * additional INSISTs + * additional logging when files can't be removed. + +2553. [bug] Reference leak on DNSSEC validation errors. [RT #19291] + +2552. [bug] zero-no-soa-ttl-cache was not being honoured. + [RT #19340] + +2551. [bug] Potential Reference leak on return. [RT #19341] + +2550. [bug] Check --with-openssl= finds . + [RT #19343] + +2549. [port] linux: define NR_OPEN if not currently defined. + [RT #19344] + +2547. [bug] openssl_link.c:mem_realloc() could reference an + out-of-range area of the source buffer. New public + function isc_mem_reallocate() was introduced to address + this bug. [RT #19313] + +2545. [doc] ARM: Legal hostname checking (check-names) is + for SRV RDATA too. [RT #19304] + +2544. [cleanup] Removed unused structure members in adb.c. [RT #19225] + +2542. [doc] Update the description of dig +adflag. [RT #19290] + +2541. [bug] Conditionally update dispatch manager statistics. + [RT #19247] + +2539. [security] Update the interaction between recursion, allow-query, + allow-query-cache and allow-recursion. [RT #19198] + +2538. [bug] cache/ADB memory could grow over max-cache-size, + especially with threads and smaller max-cache-size + values. [RT #19240] + +2537. [experimental] Added more statistics counters including those on socket + I/O events and query RTT histograms. [RT #18802] + +2536. [cleanup] Silence some warnings when -Werror=format-security is + specified. [RT #19083] + +2535. [bug] dig +showsearch and +trace interacted badly. [RT #19091] + +2532. [bug] dig: check the question section of the response to + see if it matches the asked question. [RT #18495] + +2531. [bug] Change #2207 was incomplete. [RT #19098] + +2529. [cleanup] Upgrade libtool to silence complaints from recent + version of autoconf. [RT #18657] + +2528. [cleanup] Silence spurious configure warning about + --datarootdir [RT #19096] + +2527. [bug] named could reuse cache on reload with + enabling/disabling validation. [RT #19119] + +2525. [experimental] New logging category "query-errors" to provide detailed + internal information about query failures, especially + about server failures. [RT #19027] + +2523. [bug] Random type rdata freed by dns_nsec_typepresent(). + [RT #19112] + +2522. [security] Handle -1 from DSA_do_verify(). + +2521. [bug] Improve epoll cross compilation support. [RT #19047] + +2519. [bug] dig/host with -4 or -6 didn't work if more than two + nameserver addresses of the excluded address family + preceded in resolv.conf. [RT #19081] + +2517. [bug] dig +trace with -4 or -6 failed when it chose a + nameserver address of the excluded address type. + [RT #18843] + +2516. [bug] glue sort for responses was performed even when not + needed. [RT #19039] + +2514. [bug] dig/host failed with -4 or -6 when resolv.conf contains + a nameserver of the excluded address family. + [RT #18848] + +2511. [cleanup] dns_rdata_tofmttext() add const to linebreak. + [RT #18885] + +2506. [port] solaris: Check at configure time if + hack_shutup_pthreadonceinit is needed. [RT #19037] + +2505. [port] Treat amd64 similarly to x86_64 when determining + atomic operation support. [RT #19031] + +2503. [port] linux: improve compatibility with Linux Standard + Base. [RT #18793] + +2502. [cleanup] isc_radix: Improve compliance with coding style, + document function in . [RT #18534] + +2500. [contrib] contrib/sdb/pgsql/zonetodb.c called non-existent + function. [RT #18582] + +2499. [port] solaris: lib/lwres/getaddrinfo.c namespace clash. + [RT #18837] + + --- 9.5.1 released --- + +2520. [bug] Update xml statistics version number to 2.0 as change + #2388 made the schema incompatible to the previous + version. [RT #19080] + + --- 9.5.1rc2 released --- + +2513 [bug] Fix windows cli build. [RT #19062] + +2510. [bug] "dig +sigchase" could trigger REQUIRE failures. + [RT #19033] + +2509. [bug] Specifying a fixed query source port was broken. + [RT #19051] + +2504. [bug] Address race condition in the socket code. [RT #18899] + + --- 9.5.1rc1 released --- + +2498. [bug] Removed a bogus function argument used with + ISC_SOCKET_USE_POLLWATCH: it could cause compiler + warning or crash named with the debug 1 level + of logging. [RT #18917] + +2496. [bug] Add sanity length checks to NSID option. [RT #18813] + +2495. [bug] Tighten RRSIG checks. [RT #18795] + +2494. [bug] isc/radix.h, dns/sdlz.h and dns/dlz.h were not being + installed. [RT #18826] + +2493. [bug] The linux capabilites code was not correctly cleaning + up after itself. [RT #18767] + +2490. [port] aix: work around a kernel bug where IPV6_RECVPKTINFO + is cleared when IPV6_V6ONLY is set. [RT #18785] + +2489. [port] solaris: Workaround Solaris's kernel bug about + /dev/poll: + http://bugs.opensolaris.org/view_bug.do?bug_id=6724237 + Define ISC_SOCKET_USE_POLLWATCH at build time to enable + this workaround. [RT #18870] + +2487. [bug] Give TCP connections longer to complete. [RT #18675] + +2485. [bug] Change update's the handling of obscured RRSIG + records. Not all orphand DS records were being + removed. [RT #18828] + +2482. [port] libxml2: support versions 2.7.* in addition + to 2.6.*. [RT #18806] + +2479. [bug] xfrout:covers was not properly initalized. [RT #18801] + +2478. [bug] 'addresses' could be used uninitalized in + configure_forward(). [RT #18800] + +2476. [doc] ARM: improve documentation for max-journal-size and + ixfr-from-differences. [RT #15909] [RT #18541] + + --- 9.5.1b3 released --- + +2475. [bug] LRU cache cleanup under overmem condition could purge + particular entries more aggressively. [RT #17628] + +2474. [bug] ACL structures could be allocated with insufficient + space, causing an array overrun. [RT #18765] + +2473. [port] linux: raise the limit on open files to the possible + maximum value before spawning threads; 'files' + specified in named.conf doesn't seem to work with + threads as expected. [RT #18784] + +2472. [port] linux: check the number of available cpu's before + calling chroot as it depends on "/proc". [RT #16923] + +2471. [bug] named-checkzone was not reporting missing mandatory + glue when sibling checks were disabled. [RT #18768] + +2470. [bug] Elements of the isc_radix_node_t could be incorrectly + overwritten. [RT# 18719] + +2469. [port] solaris: Work around Solaris's select() limitations. + [RT #18769] + +2468. [bug] Resolver could try unreachable servers multiple times. + [RT #18739] + +2467. [bug] Failure of fcntl(F_DUPFD) wasn't logged. [RT #18740] + +2466. [doc] ARM: explain max-cache-ttl 0 SERVFAIL issue. + [RT #18302] + +2465. [bug] Adb's handling of lame addresses was different + for IPv4 and IPv6. [RT #18738] + +2464. [port] linux: check that a capability is present before + trying to set it. [RT #18135] + +2463. [port] linux: POSIX doesn't include the IPv6 Advanced Socket + API and glibc hides parts of the IPv6 Advanced Socket + API as a result. This is stupid as it breaks how the + two halves (Basic and Advanced) of the IPv6 Socket API + were designed to be used but we have to live with it. + Define _GNU_SOURCE to pull in the IPv6 Advanced Socket + API. [RT #18388] + +2462. [doc] Document -m (enable memory usage debugging) + option for dig. [RT #18757] + +2461. [port] sunos: Change #2363 was not complete. [RT #17513] + +2458. [doc] ARM: update and correction for max-cache-size. + [RT #18294] + +2457. [tuning] max-cache-size is reverted to 0, the previous + default. It should be safe because expired cache + entries are also purged. [RT #18684] + +2456. [bug] In ACLs, ::/0 and 0.0.0.0/0 would both match any + address, regardless of family. They now correctly + distinguish IPv4 from IPv6. [RT #18559] + +2455. [bug] Stop metadata being transferred via axfr/ixfr. + [RT #18639] + +2453. [bug] Remove NULL pointer dereference in dns_journal_print(). + [RT #18316] + +2451. [port] solaris: handle runtime linking better. [RT #18356] + +2449. [bug] libbind: Out of bounds reference in dns_ho.c:addrsort. + [RT #18044] + +2445. [doc] ARM out-of-date on empty reverse zones (list includes + RFC1918 address, but these are not yet compiled in). + [RT #18578] + +2444. [port] Linux, FreeBSD, AIX: Turn off path mtu discovery + (clear DF) for UDP responses and requests. + +2387. [bug] Silence compiler warnings in lib/isc/radix.c. + [RT #18147] [RT #18258] + +2369. [bug] libbind: Array bounds overrun on read in bitncmp(). + [RT #18054] + + --- 9.5.1b2 released --- + +2443. [bug] win32: UDP connect() would not generate an event, + and so connected UDP sockets would never clean up. + Fix this by doing an immediate WSAConnect() rather + than an io completion port type for UDP. + +2442. [bug] A lock could be destroyed twice. [RT# 18626] + +2441. [bug] isc_radix_insert() could copy radix tree nodes + incompletely. [RT #18573] + +2440. [bug] named-checkconf used an incorrect test to determine + if an ACL was set to none. + +2439. [bug] Potential NULL dereference in dns_acl_isanyornone(). + [RT #18559] + +2438. [bug] Timeouts could be logged incorrectly under win32. + [RT #18617] + +2437. [bug] Sockets could be closed too early, leading to + inconsistent states in the socket module. [RT #18298] + +2436. [security] win32: UDP client handler can be shutdown. [RT #18576] + +2435. [bug] Fixed an ACL memory leak affecting win32. + +2434. [bug] Fixed a minor error-reporting bug in + lib/isc/win32/socket.c. + +2433. [tuning] Set initial timeout to 800ms. + +2432. [bug] More Windows socket handling improvements. Stop + using I/O events and use IO Completion Ports + throughout. Rewrite the receive path logic to make + it easier to support multiple simultaneous + requesters in the future. Add stricter consistency + checking as a compile-time option (define + ISC_SOCKET_CONSISTENCY_CHECKS; defaults to off). + +2431. [bug] Acl processing could leak memory. [RT #18323] + +2430. [bug] win32: isc_interval_set() could round down to + zero if the input was less than NS_INTERVAL + nanoseconds. Round up instead. [RT #18549] + +2429. [doc] nsupdate should be in section 1 of the man pages. + [RT #18283] + +2428. [bug] dns_iptable_merge() mishandled merges of negative + tables. [RT #18409] + +2426. [bug] libbind: inet_net_pton() can sometimes return the + wrong value if excessively large net masks are + supplied. [RT #18512] + +2425. [bug] named didn't detect unavailable query source addresses + at load time. [RT #18536] + +2424. [port] configure now probes for a working epoll + implementation. Allow the use of kqueue, + epoll and /dev/poll to be selected at compile + time. [RT #18277] + +2422. [bug] Handle the special return value of a empty node as + if it was a NXRRSET in the validator. [RT #18447] + +2421. [func] Add new command line option '-S' for named to specify + the max number of sockets. [RT #18493] + Use caution: this option may not work for some + operating systems without rebuilding named. + +2420. [bug] Windows socket handling cleanup. Let the io + completion event send out cancelled read/write + done events, which keeps us from writing to memory + we no longer have ownership of. Add debugging + socket_log() function. Rework TCP socket handling + to not leak sockets. + +2419. [cleanup] Document that isc_socket_create() and isc_socket_open() + should not be used for isc_sockettype_fdwatch sockets. + [RT #18521] + +2418. [bug] AXFR request on a DLZ could trigger a REQUIRE failure + [RT #18430] + +2417. [bug] Connecting UDP sockets for outgoing queries could + unexpectedly fail with an 'address already in use' + error. [RT #18411] + +2416. [func] Log file descriptors that cause exceeding the + internal maximum. [RT #18460] + +2415. [bug] 'rndc dumpdb' could trigger various assertion failures + in rbtdb.c. [RT #18455] + +2414. [bug] A masterdump context held the database lock too long, + causing various troubles such as dead lock and + recursive lock acquisition. [RT #18311, #18456] + +2413. [bug] Fixed an unreachable code path in socket.c. [RT #18442] + +2412. [bug] win32: address a resourse leak. [RT #18374] + +2411. [bug] Allow using a larger number of sockets than FD_SETSIZE + for select(). To enable this, set ISC_SOCKET_MAXSOCKETS + at compilation time. [RT #18433] + + Note: with changes #2469 and #2421 above, there is no + need to tweak ISC_SOCKET_MAXSOCKETS at compilation time + any more. + +2410. [bug] Correctly delete m_versionInfo. [RT #18432] + +2409. [bug] Only log that we disabled EDNS processing if we were + subsequently successful. [RT #18029] + +2408. [bug] A duplicate TCP dispatch event could be sent, which + could then trigger an assertion failure in + resquery_response(). [RT #18275] + +2407. [port] hpux: test for sys/dyntune.h. [RT #18421] + +2405. [cleanup] The default value for dnssec-validation was changed to + "yes" in 9.5.0-P1 and all subsequent releases; this + was inadvertently omitted from CHANGES at the time. + +2404. [port] hpux: files unlimited support. + +2403. [bug] TSIG context leak. [RT #18341] + +2402. [port] Support Solaris 2.11 and over. [RT #18362] + +2401. [bug] Expect to get E[MN]FILE errno internal_accept() + (from accept() or fcntl() system calls). [RT #18358] + +2400. [bug] Log if kqueue()/epoll_create()/open(/dev/poll) fails. + [RT #18297] + +2398. [bug] Improve file descriptor management. New, + temporary, named.conf option reserved-sockets, + default 512. [RT #18344] + +2397. [bug] gssapi_functions bad declaration. [RT #18355] + +2396. [bug] Don't set SO_REUSEADDR for randomized ports. + [RT #18336] + +2395. [port] Avoid warning and no effect from "files unlimited" + on Linux when running as root. [RT #18335] + +2394. [bug] Default configuration options set the limit for + open files to 'unlimited' as described in the + documentation. [RT #18331] + +2393. [bug] nested acls containing keys could trigger an + assertion in acl.c. [RT #18166] + +2392. [bug] remove 'grep -q' from acl test script, some platforms + don't support it. [RT #18253] + +2391. [port] hpux: cover additional recvmsg() error codes. + [RT #18301] + +2390. [bug] dispatch.c could make a false warning on 'odd socket'. + [RT #18301]. + +2389. [bug] Move the "working directory writable" check to after + the ns_os_changeuser() call. [RT #18326] + +2388. [bug] Avoid using tables for layout purposes in + statistics XSL [RT #18159]. + +2386. [func] Add warning about too small 'open files' limit. + [RT #18269] + + --- 9.5.1b1 released --- + +2385. [bug] A condition variable in socket.c could leak in + rare error handling [RT #17968]. + +2384. [security] Additional support for query port randomization (change + #2375) including performance improvement and port range + specification. [RT #17949, #18098] + +2383. [bug] named could double queries when they resulted in + SERVFAIL due to overkilling EDNS0 failure detection. + [RT #18182] + +2382. [doc] Add descriptions of DHCID, IPSECKEY, SPF and SSHFP + to ARM. + +2381. [port] dlz/mysql: support multiple install layouts for + mysql. /include/{,mysql/}mysql.h and + /lib/{,mysql/}. [RT #18152] + +2380. [bug] dns_view_find() was not returning NXDOMAIN/NXRRSET + proofs which, in turn, caused validation failures + for insecure zones immediately below a secure zone + the server was authoritative for. [RT #18112] + +2379. [contrib] queryperf/gen-data-queryperf.py: removed redundant + TLDs and supported RRs with TTLs [RT #17972] + +2378. [bug] gssapi_functions{} had a redundant member in BIND 9.5. + [RT #18169] + +2377. [bug] Address race condition in dnssec-signzone. [RT #18142] + +2376. [bug] Change #2144 was not complete. + +2375. [security] Fully randomize UDP query ports to improve + forgery resilience. [RT #17949] + +2373. [bug] Default values of zone ACLs were re-parsed each time a + new zone was configured, causing an overconsumption + of memory. [RT #18092] + + --- 9.5.0 released --- + +2374. [bug] "blackhole" ACLs could cause named to segfault due + to some uninitialized memory. [RT #18095] + +2372. [bug] fixed incorrect TAG_HMACSHA256_BITS value [RT #18047] + +2371. [doc] add +nsid option to dig man page. [RT #18039] + +2370. [bug] "rndc freeze" could trigger an assertion in named + when called on a nonexistent zone. [RT #18050] + + --- 9.5.0rc1 released --- + +2368. [port] Linux: use libcap for capability management if + possible. [RT# 18026] + +2367. [bug] Improve counting of dns_resstatscounter_retry + [RT #18030] + +2366. [bug] Adb shutdown race. [RT #18021] + +2365. [bug] Fix a bug that caused dns_acl_isany() to return + spurious results. [RT #18000] + +2364. [bug] named could trigger an assertion when serving a + malformed signed zone. [RT #17828] + +2363. [port] sunos: pre-set "lt_cv_sys_max_cmd_len=4096;". + [RT #17513] + +2362. [cleanup] Make "rrset-order fixed" a compile-time option. + settable by "./configure --enable-fixed-rrset". + Disabled by default. [RT #17977] + +2361. [bug] "recursion" statistics counter could be counted + multiple times for a single query. [RT #17990] + + --- 9.5.0b3 released --- + +2360. [bug] Fix a condition where we release a database version + (which may acquire a lock) while holding the lock. + +2359. [bug] Fix NSID bug. [RT #17942] + +2358. [doc] Update host's default query description. [RT #17934] + +2356. [bug] Built in mutex profiler was not scalable enough. + [RT #17436] + +2355. [func] Extend the number statistics counters available. + [RT #17590] + +2354. [bug] Failed to initialize some rdatasetheader_t elements. + [RT #17927] + +2353. [func] Add support for Name Server ID (RFC 5001). + 'dig +nsid' requests NSID from server. + 'request-nsid yes;' causes recursive server to send + NSID requests to upstream servers. Server responds + to NSID requests with the string configured by + 'server-id' option. [RT #17091] + +2352. [bug] Various GSS_API fixups. [RT #17729] + +2351. [bug] convertxsl.pl generated very long lines. [RT #17906] + +2350. [port] win32: IPv6 support. [RT #17797] + +2347. [bug] Delete now traverses the RB tree in the canonical + order. [RT #17451] + +2346. [func] Memory statistics now cover all active memory contexts + in increased detail. [RT #17580] + +2345. [bug] named-checkconf failed to detect when forwarders + were set at both the options/view level and in + a root zone. [RT #17671] + +2344. [bug] Improve "logging{ file ...; };" documentation. + [RT #17888] + +2343. [bug] (Seemingly) duplicate IPv6 entries could be + created in ADB. [RT #17837] + +2341. [bug] libbind: add missing -I../include for off source + tree builds. [RT #17606] + +2340. [port] openbsd: interface configuration. [RT #17700] + +2339. [port] tru64: support for libbind. [RT #17589] + +2338. [bug] check_ds() could be called with a non DS rdataset. + [RT #17598] + +2337. [bug] BUILD_LDFLAGS was not being correctly set. [RT #17614] + +2335. [port] sunos: libbind and *printf() support for long long. + [RT #17513] + +2334. [bug] Bad REQUIRES in fromstruct_in_naptr(), off by one + bug in fromstruct_txt(). [RT #17609] + +2333. [bug] Fix off by one error in isc_time_nowplusinterval(). + [RT #17608] + +2332. [contrib] query-loc-0.4.0. [RT #17602] + +2331. [bug] Failure to regenerate any signatures was not being + reported nor being past back to the UPDATE client. + [RT #17570] + +2330. [bug] Remove potential race condition when handling + over memory events. [RT #17572] + + WARNING: API CHANGE: over memory callback + function now needs to call isc_mem_waterack(). + See for details. + +2329. [bug] Clearer help text for dig's '-x' and '-i' options. + +2328. [maint] Add AAAA addresses for A.ROOT-SERVERS.NET, + F.ROOT-SERVERS.NET, H.ROOT-SERVERS.NET, + J.ROOT-SERVERS.NET, K.ROOT-SERVERS.NET and + M.ROOT-SERVERS.NET. + +2327. [bug] It was possible to dereference a NULL pointer in + rbtdb.c. Implement dead node processing in zones as + we do for caches. [RT #17312] + +2326. [bug] It was possible to trigger a INSIST in the acache + processing. + +2325. [port] Linux: use capset() function if available. [RT #17557] + + --- 9.5.0b2 released --- + +2324. [bug] Fix IPv6 matching against "any;". [RT #17533] + +2323. [port] tru64: namespace clash. [RT #17547] + +2322. [port] MacOS: work around the limitation of setrlimit() + for RLIMIT_NOFILE. [RT #17526] + +2320. [func] Make statistics counters thread-safe for platforms + that support certain atomic operations. [RT #17466] + +2319. [bug] Silence Coverity warnings in + lib/dns/rdata/in_1/apl_42.c. [RT #17469] + +2318. [port] sunos fixes for libbind. [RT #17514] + +2317. [bug] "make distclean" removed bind9.xsl.h. [RT #17518] + +2316. [port] Missing #include in lib/dns/gssapictx.c. + [RT #17513] + +2315. [bug] Used incorrect address family for mapped IPv4 + addresses in acl.c. [RT #17519] + +2314. [bug] Uninitialized memory use on error path in + bin/named/lwdnoop.c. [RT #17476] + +2313. [cleanup] Silence Coverity warnings. Handle private stacks. + [RT #17447] [RT #17478] + +2312. [cleanup] Silence Coverity warning in lib/isc/unix/socket.c. + [RT #17458] + +2311. [bug] IPv6 addresses could match IPv4 ACL entries and + vice versa. [RT #17462] + +2310. [bug] dig, host, nslookup: flush stdout before emitting + debug/fatal messages. [RT #17501] + +2309. [cleanup] Fix Coverity warnings in lib/dns/acl.c and iptable.c. + [RT #17455] + +2308. [cleanup] Silence Coverity warning in bin/named/controlconf.c. + [RT #17495] + +2307. [bug] Remove infinite loop from lib/dns/sdb.c. [RT #17496] + +2306. [bug] Remove potential race from lib/dns/resolver.c. + [RT #17470] + +2305. [security] inet_network() buffer overflow. CVE-2008-0122. + +2304. [bug] Check returns from all dns_rdata_tostruct() calls. + [RT #17460] + +2303. [bug] Remove unnecessary code from bin/named/lwdgnba.c. + [RT #17471] + +2302. [bug] Fix memset() calls in lib/tests/t_api.c. [RT #17472] + +2301. [bug] Remove resource leak and fix error messages in + bin/tests/system/lwresd/lwtest.c. [RT #17474] + +2300. [bug] Fixed failure to close open file in + bin/tests/names/t_names.c. [RT #17473] + +2299. [bug] Remove unnecessary NULL check in + bin/nsupdate/nsupdate.c. [RT #17475] + +2298. [bug] isc_mutex_lock() failure not caught in + bin/tests/timers/t_timers.c. [RT #17468] + +2297. [bug] isc_entropy_createfilesource() failure not caught in + bin/tests/dst/t_dst.c. [RT #17467] + +2296. [port] Allow docbook stylesheet location to be specified to + configure. [RT #17457] + +2295. [bug] Silence static overrun error in bin/named/lwaddr.c. + [RT #17459] + +2294. [func] Allow the experimental statistics channels to have + multiple connections and ACL. + Note: the stats-server and stats-server-v6 options + available in the previous beta releases are replaced + with the generic statistics-channels statement. + +2293. [func] Add ACL regression test. [RT #17375] + +2292. [bug] Log if the working directory is not writable. + [RT #17312] + +2291. [bug] PR_SET_DUMPABLE may be set too late. Also report + failure to set PR_SET_DUMPABLE. [RT #17312] + +2290. [bug] Let AD in the query signal that the client wants AD + set in the response. [RT #17301] + +2288. [port] win32: mark service as running when we have finished + loading. [RT #17441] + +2287. [bug] Use 'volatile' if the compiler supports it. [RT #17413] + +2284. [bug] Memory leak in UPDATE prerequisite processing. + [RT #17377] + +2283. [bug] TSIG keys were not attaching to the memory + context. TSIG keys should use the rings + memory context rather than the clients memory + context. [RT #17377] + +2282. [bug] Acl code fixups. [RT #17346] [RT #17374] + +2281. [bug] Attempts to use undefined acls were not being logged. + [RT #17307] + +2280. [func] Allow the experimental http server to be reached + over IPv6 as well as IPv4. [RT #17332] + +2279. [bug] Use setsockopt(SO_NOSIGPIPE), when available, + to protect applications from receiving spurious + SIGPIPE signals when using the resolver. + +2278. [bug] win32: handle the case where Windows returns no + search list or DNS suffix. [RT #17354] + +2277. [bug] Empty zone names were not correctly being caught at + in the post parse checks. [RT #17357] + +2276. [bug] Install . [RT# 17359] + +2275. [func] Add support to dig to perform IXFR queries over UDP. + [RT #17235] + +2274. [func] Log zone transfer statistics. [RT #17336] + +2273. [bug] Adjust log level to WARNING when saving inconsistent + stub/slave master and journal files. [RT# 17279] + +2272. [bug] Handle illegal dnssec-lookaside trust-anchor names. + [RT #17262] + +2271. [bug] Fix a memory leak in http server code [RT #17100] + +2270. [bug] dns_db_closeversion() version->writer could be reset + before it is tested. [RT #17290] + +2269. [contrib] dbus memory leaks and missing va_end calls. [RT #17232] + +2268. [bug] 0.IN-ADDR.ARPA was missing from the empty zones + list. + + --- 9.5.0b1 released --- + +2267. [bug] Radix tree node_num value could be set incorrectly, + causing positive ACL matches to look like negative + ones. [RT #17311] + +2266. [bug] client.c:get_clientmctx() returned the same mctx + once the pool of mctx's was filled. [RT #17218] + +2265. [bug] Test that the memory context's basic_table is non NULL + before freeing. [RT #17265] + +2264. [bug] Server prefix length was being ignored. [RT #17308] + +2263. [bug] "named-checkconf -z" failed to set default value + for "check-integrity". [RT #17306] + +2262. [bug] Error status from all but the last view could be + lost. [RT #17292] + +2261. [bug] Fix memory leak with "any" and "none" ACLs [RT #17272] + +2260. [bug] Reported wrong clients-per-query when increasing the + value. [RT #17236] + +2259. [placeholder] + + --- 9.5.0a7 released --- + +2258. [bug] Fallback from IXFR/TSIG to SOA/AXFR/TSIG broken. + [RT #17241] + +2257. [bug] win32: Use the full path to vcredist_x86.exe when + calling it. [RT #17222] + +2256. [bug] win32: Correctly register the installation location of + bindevt.dll. [RT #17159] + +2255. [maint] L.ROOT-SERVERS.NET is now 199.7.83.42. + +2254. [bug] timer.c:dispatch() failed to lock timer->lock + when reading timer->idle allowing it to see + intermediate values as timer->idle was reset by + isc_timer_touch(). [RT #17243] + +2253. [func] "max-cache-size" defaults to 32M. + "max-acache-size" defaults to 16M. + +2252. [bug] Fixed errors in sortlist code [RT #17216] + +2251. [placeholder] + +2250. [func] New flag 'memstatistics' to state whether the + memory statistics file should be written or not. + Additionally named's -m option will cause the + statistics file to be written. [RT #17113] + +2249. [bug] Only set Authentic Data bit if client requested + DNSSEC, per RFC 3655 [RT #17175] + +2248. [cleanup] Fix several errors reported by Coverity. [RT #17160] + +2247. [doc] Sort doc/misc/options. [RT #17067] + +2246. [bug] Make the startup of test servers (ans.pl) more + robust. [RT #17147] + +2245. [bug] Validating lack of DS records at trust anchors wasn't + working. [RT #17151] + +2244. [func] Allow the check of nameserver names against the + SOA MNAME field to be disabled by specifying + 'notify-to-soa yes;'. [RT #17073] + +2243. [func] Configuration files without a newline at the end now + parse without error. [RT #17120] + +2242. [bug] nsupdate: GSS-TSIG support using the Heimdal Kerberos + library could require a source of random data. + [RT #17127] + +2241. [func] nsupdate: add a interactive 'help' command. [RT #17099] + +2240. [bug] Cleanup nsupdates GSS-TSIG support. Convert + a number of INSIST()s into plain fatal() errors + which report the triggering result code. + The 'key' command wasn't disabling GSS-TSIG. + [RT #17099] + +2239. [func] Ship a pre built bin/named/bind9.xsl.h. [RT #17114] + +2238. [bug] It was possible to trigger a REQUIRE when a + validation was canceled. [RT #17106] + +2237. [bug] libbind: res_init() was not thread aware. [RT #17123] + +2236. [bug] dnssec-signzone failed to preserve the case of + of wildcard owner names. [RT #17085] + +2235. [bug] was not being installed. [RT #17135] + +2234. [port] Correct some compiler warnings on SCO OSr5 [RT #17134] + +2233. [func] Add support for O(1) ACL processing, based on + radix tree code originally written by Kevin + Brintnall. [RT #16288] + +2232. [bug] dns_adb_findaddrinfo() could fail and return + ISC_R_SUCCESS. [RT #17137] + +2231. [bug] Building dlzbdb (contrib/dlz/bin/dlzbdb) was broken. + [RT #17088] + +2230. [bug] We could INSIST reading a corrupted journal. + [RT #17132] + +2229. [bug] Null pointer dereference on query pool creation + failure. [RT #17133] + +2228. [contrib] contrib: Change 2188 was incomplete. + +2227. [cleanup] Tidied up the FAQ. [RT #17121] + +2226. [placeholder] + +2225. [bug] More support for systems with no IPv4 addresses. + [RT #17111] + +2224. [bug] Defer journal compaction if a xfrin is in progress. + [RT #17119] + +2223. [bug] Make a new journal when compacting. [RT #17119] + +2222. [func] named-checkconf now checks server key references. + [RT #17097] + +2221. [bug] Set the event result code to reflect the actual + record turned to caller when a cache update is + rejected due to a more credible answer existing. + [RT #17017] + +2220. [bug] win32: Address a race condition in final shutdown of + the Windows socket code. [RT #17028] + +2219. [bug] Apply zone consistency checks to additions, not + removals, when updating. [RT #17049] + +2218. [bug] Remove unnecessary REQUIRE from dns_validator_create(). + [RT #16976] + +2217. [func] Adjust update log levels. [RT #17092] + +2216. [cleanup] Fix a number of errors reported by Coverity. + [RT #17094] + +2215. [bug] Bad REQUIRE check isc_hmacsha1_verify(). [RT #17094] + +2214. [bug] Deregister OpenSSL lock callback when cleaning + up. Reorder OpenSSL cleanup so that RAND_cleanup() + is called before the locks are destroyed. [RT #17098] + +2213. [bug] SIG0 diagnostic failure messages were looking at the + wrong status code. [RT #17101] + +2212. [func] 'host -m' now causes memory statistics and active + memory to be printed at exit. [RT 17028] + +2211. [func] Update "dynamic update temporarily disabled" message. + [RT #17065] + +2210. [bug] Deleting class specific records via UPDATE could + fail. [RT #17074] + +2209. [port] osx: linking against user supplied static OpenSSL + libraries failed as the system ones were still being + found. [RT #17078] + +2208. [port] win32: make sure both build methods produce the + same output. [RT #17058] + +2207. [port] Some implementations of getaddrinfo() fail to set + ai_canonname correctly. [RT #17061] + + --- 9.5.0a6 released --- + +2206. [security] "allow-query-cache" and "allow-recursion" now + cross inherit from each other. + + If allow-query-cache is not set in named.conf then + allow-recursion is used if set, otherwise allow-query + is used if set, otherwise the default (localnets; + localhost;) is used. + + If allow-recursion is not set in named.conf then + allow-query-cache is used if set, otherwise allow-query + is used if set, otherwise the default (localnets; + localhost;) is used. + + [RT #16987] + +2205. [bug] libbind: change #2119 broke thread support. [RT #16982] + +2204. [bug] "rndc flushanme name unknown-view" caused named + to crash. [RT #16984] + +2203. [security] Query id generation was cryptographically weak. + [RT # 16915] + +2202. [security] The default acls for allow-query-cache and + allow-recursion were not being applied. [RT #16960] + +2201. [bug] The build failed in a separate object directory. + [RT #16943] + +2200. [bug] The search for cached NSEC records was stopping to + early leading to excessive DLV queries. [RT #16930] + +2199. [bug] win32: don't call WSAStartup() while loading dlls. + [RT #16911] + +2198. [bug] win32: RegCloseKey() could be called when + RegOpenKeyEx() failed. [RT #16911] + +2197. [bug] Add INSIST to catch negative responses which are + not setting the event result code appropriately. + [RT #16909] + +2196. [port] win32: yield processor while waiting for once to + to complete. [RT #16958] + +2195. [func] dnssec-keygen now defaults to nametype "ZONE" + when generating DNSKEYs. [RT #16954] + +2194. [bug] Close journal before calling 'done' in xfrin.c. + + --- 9.5.0a5 released --- + +2193. [port] win32: BINDInstall.exe is now linked statically. + [RT #16906] + +2192. [port] win32: use vcredist_x86.exe to install Visual + Studio's redistributable dlls if building with + Visual Stdio 2005 or later. + +2191. [func] named-checkzone now allows dumping to stdout (-). + named-checkconf now has -h for help. + named-checkzone now has -h for help. + rndc now has -h for help. + Better handling of '-?' for usage summaries. + [RT #16707] + +2190. [func] Make fallback to plain DNS from EDNS due to timeouts + more visible. New logging category "edns-disabled". + [RT #16871] + +2189. [bug] Handle socket() returning EINTR. [RT #15949] + +2188. [contrib] queryperf: autoconf changes to make the search for + libresolv or libbind more robust. [RT #16299] + +2187. [bug] query_addds(), query_addwildcardproof() and + query_addnxrrsetnsec() should take a version + argument. [RT #16368] + +2186. [port] cygwin: libbind: check for struct sockaddr_storage + independently of IPv6. [RT #16482] + +2185. [port] sunos: libbind: check for ssize_t, memmove() and + memchr(). [RT #16463] + +2184. [bug] bind9.xsl.h didn't build out of the source tree. + [RT #16830] + +2183. [bug] dnssec-signzone didn't handle offline private keys + well. [RT #16832] + +2182. [bug] dns_dispatch_createtcp() and dispatch_createudp() + could return ISC_R_SUCCESS when they ran out of + memory. [RT #16365] + +2181. [port] sunos: libbind: add paths.h from BIND 8. [RT #16462] + +2180. [cleanup] Remove bit test from 'compress_test' as they + are no longer needed. [RT #16497] + +2179. [func] 'rndc command zone' will now find 'zone' if it is + unique to all the views. [RT #16821] + +2178. [bug] 'rndc reload' of a slave or stub zone resulted in + a reference leak. [RT #16867] + +2177. [bug] Array bounds overrun on read (rcodetext) at + debug level 10+. [RT #16798] + +2176. [contrib] dbus update to handle race condition during + initialization (Bugzilla 235809). [RT #16842] + +2175. [bug] win32: windows broadcast condition variable support + was broken. [RT #16592] + +2174. [bug] I/O errors should always be fatal when reading + master files. [RT #16825] + +2173. [port] win32: When compiling with MSVS 2005 SP1 we also + need to ship Microsoft.VC80.MFCLOC. + + --- 9.5.0a4 released --- + +2172. [bug] query_addsoa() was being called with a non zone db. + [RT #16834] + +2171. [bug] Handle breaks in DNSSEC trust chains where the parent + servers are not DS aware (DS queries to the parent + return a referral to the child). + +2170. [func] Add acache processing to test suite. [RT #16711] + +2169. [bug] host, nslookup: when reporting NXDOMAIN report the + given name and not the last name searched for. + [RT #16763] + +2168. [bug] nsupdate: in non-interactive mode treat syntax errors + as fatal errors. [RT #16785] + +2167. [bug] When re-using a automatic zone named failed to + attach it to the new view. [RT #16786] + + --- 9.5.0a3 released --- + +2166. [bug] When running in batch mode, dig could misinterpret + a server address as a name to be looked up, causing + unexpected output. [RT #16743] + +2165. [func] Allow the destination address of a query to determine + if we will answer the query or recurse. + allow-query-on, allow-recursion-on and + allow-query-cache-on. [RT #16291] + +2164. [bug] The code to determine how named-checkzone / + named-compilezone was called failed under windows. + [RT #16764] + +2163. [bug] If only one of query-source and query-source-v6 + specified a port the query pools code broke (change + 2129). [RT #16768] + +2162. [func] Allow "rrset-order fixed" to be disabled at compile + time. [RT #16665] + +2161. [bug] Fix which log messages are emitted for 'rndc flush'. + [RT #16698] + +2160. [bug] libisc wasn't handling NULL ifa_addr pointers returned + from getifaddrs(). [RT #16708] + + --- 9.5.0a2 released --- + +2159. [bug] Array bounds overrun in acache processing. [RT #16710] + +2158. [bug] ns_client_isself() failed to initialize key + leading to a REQUIRE failure. [RT #16688] + +2157. [func] dns_db_transfernode() created. [RT #16685] + +2156. [bug] Fix node reference leaks in lookup.c:lookup_find(), + resolver.c:validated() and resolver.c:cache_name(). + Fix a memory leak in rbtdb.c:free_noqname(). + Make lookup.c:lookup_find() robust against + event leaks. [RT #16685] + +2155. [contrib] SQLite sdb module from jaboydjr@netwalk.com. + [RT #16694] + +2154. [func] Scoped (e.g. IPv6 link-local) addresses may now be + matched in acls by omitting the scope. [RT #16599] + +2153. [bug] nsupdate could leak memory. [RT #16691] + +2152. [cleanup] Use sizeof(buf) instead of fixed number in + dighost.c:get_trusted_key(). [RT #16678] + +2151. [bug] Missing newline in usage message for journalprint. + [RT #16679] + +2150. [bug] 'rrset-order cyclic' uniformly distribute the + starting point for the first response for a given + RRset. [RT #16655] + +2149. [bug] isc_mem_checkdestroyed() failed to abort on + if there were still active memory contexts. + [RT #16672] + +2148. [func] Add positive logging for rndc commands. [RT #14623] + +2147. [bug] libbind: remove potential buffer overflow from + hmac_link.c. [RT #16437] + +2146. [cleanup] Silence Linux's spurious "obsolete setsockopt + SO_BSDCOMPAT" message. [RT #16641] + +2145. [bug] Check DS/DLV digest lengths for known digests. + [RT #16622] + +2144. [cleanup] Suppress logging of SERVFAIL from forwarders. + [RT #16619] + +2143. [bug] We failed to restart the IPv6 client when the + kernel failed to return the destination the + packet was sent to. [RT #16613] + +2142. [bug] Handle master files with a modification time that + matches the epoch. [RT# 16612] + +2141. [bug] dig/host should not be setting IDN_ASCCHECK (IDN + equivalent of LDH checks). [RT #16609] + +2140. [bug] libbind: missing unlock on pthread_key_create() + failures. [RT #16654] + +2139. [bug] dns_view_find() was being called with wrong type + in adb.c. [RT #16670] + +2138. [bug] Lock order reversal in resolver.c. [RT #16653] + +2137. [port] Mips little endian and/or mips 64 bit are now + supported for atomic operations. [RT#16648] + +2136. [bug] nslookup/host looped if there was no search list + and the host didn't exist. [RT #16657] + +2135. [bug] Uninitialized rdataset in sdlz.c. [RT# 16656] + +2134. [func] Additional statistics support. [RT #16666] + +2133. [port] powerpc: Support both IBM and MacOS Power PC + assembler syntaxes. [RT #16647] + +2132. [bug] Missing unlock on out of memory in + dns_dispatchmgr_setudp(). + +2131. [contrib] dlz/mysql: AXFR was broken. [RT #16630] + +2130. [func] Log if CD or DO were set. [RT #16640] + +2129. [func] Provide a pool of UDP sockets for queries to be + made over. See use-queryport-pool, queryport-pool-ports + and queryport-pool-updateinterval. [RT #16415] + +2128. [doc] xsltproc --nonet, update DTD versions. [RT #16635] + +2127. [port] Improved OpenSSL 0.9.8 support. [RT #16563] + +2126. [security] Serialize validation of type ANY responses. [RT #16555] + +2125. [bug] dns_zone_getzeronosoattl() REQUIRE failure if DLZ + was defined. [RT #16574] + +2124. [security] It was possible to dereference a freed fetch + context. [RT #16584] + + --- 9.5.0a1 released --- + +2123. [func] Use Doxygen to generate internal documentation. + [RT #11398] + +2122. [func] Experimental http server and statistics support + for named via xml. + +2121. [func] Add a 10 slot dead masters cache (LRU) with a 600 + second timeout. [RT #16553] + +2120. [doc] Fix markup on nsupdate man page. [RT #16556] + +2119. [compat] libbind: allow res_init() to succeed enough to + return the default domain even if it was unable + to allocate memory. + +2118. [bug] Handle response with long chains of domain name + compression pointers which point to other compression + pointers. [RT #16427] + +2117. [bug] DNSSEC fixes: named could fail to cache NSEC records + which could lead to validation failures. named didn't + handle negative DS responses that were in the process + of being validated. Check CNAME bit before accepting + NODATA proof. To be able to ignore a child NSEC there + must be SOA (and NS) set in the bitmap. [RT #16399] + +2116. [bug] 'rndc reload' could cause the cache to continually + be cleaned. [RT #16401] + +2115. [bug] 'rndc reconfig' could trigger a INSIST if the + number of masters for a zone was reduced. [RT #16444] + +2114. [bug] dig/host/nslookup: searches for names with multiple + labels were failing. [RT #16447] + +2113. [bug] nsupdate: if a zone is specified it should be used + for server discover. [RT# 16455] + +2112. [security] Warn if weak RSA exponent is used. [RT #16460] + +2111. [bug] Fix a number of errors reported by Coverity. + [RT #16507] + +2110. [bug] "minimal-responses yes;" interacted badly with BIND 8 + priming queries. [RT #16491] + +2109. [port] libbind: silence aix 5.3 compiler warnings. [RT #16502] + +2108. [func] DHCID support. [RT #16456] + +2107. [bug] dighost.c: more cleanup of buffers. [RT #16499] + +2106. [func] 'rndc status' now reports named's version. [RT #16426] + +2105. [func] GSS-TSIG support (RFC 3645). + +2104. [port] Fix Solaris SMF error message. + +2103. [port] Add /usr/sfw to list of locations for OpenSSL + under Solaris. + +2102. [port] Silence Solaris 10 warnings. + +2101. [bug] OpenSSL version checks were not quite right. + [RT #16476] + +2100. [port] win32: copy libeay32.dll to Build\Debug. + Copy Debug\named-checkzone to Debug\named-compilezone. + +2099. [port] win32: more manifest issues. + +2098. [bug] Race in rbtdb.c:no_references(), which occasionally + triggered an INSIST failure about the node lock + reference. [RT #16411] + +2097. [bug] named could reference a destroyed memory context + after being reloaded / reconfigured. [RT #16428] + +2096. [bug] libbind: handle applications that fail to detect + res_init() failures better. + +2095. [port] libbind: alway prototype inet_cidr_ntop_ipv6() and + net_cidr_ntop_ipv6(). [RT #16388] + +2094. [contrib] Update named-bootconf. [RT# 16404] + +2093. [bug] named-checkzone -s was broken. + +2092. [bug] win32: dig, host, nslookup. Use registry config + if resolv.conf does not exist or no nameservers + listed. [RT #15877] + +2091. [port] dighost.c: race condition on cleanup. [RT #16417] + +2090. [port] win32: Visual C++ 2005 command line manifest support. + [RT #16417] + +2089. [security] Raise the minimum safe OpenSSL versions to + OpenSSL 0.9.7l and OpenSSL 0.9.8d. Versions + prior to these have known security flaws which + are (potentially) exploitable in named. [RT #16391] + +2088. [security] Change the default RSA exponent from 3 to 65537. + [RT #16391] + +2087. [port] libisc failed to compile on OS's w/o a vsnprintf. + [RT #16382] + +2086. [port] libbind: FreeBSD now has get*by*_r() functions. + [RT #16403] + +2085. [doc] win32: added index.html and README to zip. [RT #16201] + +2084. [contrib] dbus update for 9.3.3rc2. + +2083. [port] win32: Visual C++ 2005 support. + +2082. [doc] Document 'cache-file' as a test only option. + +2081. [port] libbind: minor 64-bit portability fix in memcluster.c. + [RT #16360] + +2080. [port] libbind: res_init.c did not compile on older versions + of Solaris. [RT #16363] + +2079. [bug] The lame cache was not handling multiple types + correctly. [RT #16361] + +2078. [bug] dnssec-checkzone output style "default" was badly + named. It is now called "relative". [RT #16326] + +2077. [bug] 'dnssec-signzone -O raw' wasn't outputting the + complete signed zone. [RT #16326] + +2076. [bug] Several files were missing #include + causing build failures on OSF. [RT #16341] + +2075. [bug] The spillat timer event hander could leak memory. + [RT #16357] + +2074. [bug] dns_request_createvia2(), dns_request_createvia3(), + dns_request_createraw2() and dns_request_createraw3() + failed to send multiple UDP requests. [RT #16349] + +2073. [bug] Incorrect semantics check for update policy "wildcard". + [RT #16353] + +2072. [bug] We were not generating valid HMAC SHA digests. + [RT #16320] + +2071. [port] Test whether gcc accepts -fno-strict-aliasing. + [RT #16324] + +2070. [bug] The remote address was not always displayed when + reporting dispatch failures. [RT #16315] + +2069. [bug] Cross compiling was not working. [RT #16330] + +2068. [cleanup] Lower incremental tuning message to debug 1. + [RT #16319] + +2067. [bug] 'rndc' could close the socket too early triggering + a INSIST under Windows. [RT #16317] + +2066. [security] Handle SIG queries gracefully. [RT #16300] + +2065. [bug] libbind: probe for HPUX prototypes for + endprotoent_r() and endservent_r(). [RT 16313] + +2064. [bug] libbind: silence AIX compiler warnings. [RT #16218] + +2063. [bug] Change #1955 introduced a bug which caused the first + 'rndc flush' call to not free memory. [RT #16244] + +2062. [bug] 'dig +nssearch' was reusing a buffer before it had + been returned by the socket code. [RT #16307] + +2061. [bug] Accept expired wildcard message reversed. [RT #16296] + +2060. [bug] Enabling DLZ support could leave views partially + configured. [RT #16295] + +2059. [bug] Search into cache rbtdb could trigger an INSIST + failure while cleaning up a stale rdataset. + [RT #16292] + +2058. [bug] Adjust how we calculate rtt estimates in the presence + of authoritative servers that drop EDNS and/or CD + requests. Also fallback to EDNS/512 and plain DNS + faster for zones with less than 3 servers. [RT #16187] + +2057. [bug] Make setting "ra" dependent on both allow-query-cache + and allow-recursion. [RT #16290] + +2056. [bug] dig: ixfr= was not being treated case insensitively + at all times. [RT #15955] + +2055. [bug] Missing goto after dropping multicast query. + [RT #15944] + +2054. [port] freebsd: do not explicitly link against -lpthread. + [RT #16170] + +2053. [port] netbsd:libbind: silence compiler warnings. [RT #16220] + +2052. [bug] 'rndc' improve connect failed message to report + the failing address. [RT #15978] + +2051. [port] More strtol() fixes. [RT #16249] + +2050. [bug] Parsing of NSAP records was not case insensitive. + [RT #16287] + +2049. [bug] Restore SOA before AXFR when falling back from + a attempted IXFR when transferring in a zone. + Allow a initial SOA query before attempting + a AXFR to be requested. [RT #16156] + +2048. [bug] It was possible to loop forever when using + avoid-v4-udp-ports / avoid-v6-udp-ports when + the OS always returned the same local port. + [RT #16182] + +2047. [bug] Failed to initialize the interface flags to zero. + [RT #16245] + +2046. [bug] rbtdb.c:rdataset_setadditional() could cause duplicate + cleanup [RT #16247]. + +2045. [func] Use lock buckets for acache entries to limit memory + consumption. [RT #16183] + +2044. [port] Add support for atomic operations for Itanium. + [RT #16179] + +2043. [port] nsupdate/nslookup: Force the flushing of the prompt + for interactive sessions. [RT#16148] + +2042. [bug] named-checkconf was incorrectly rejecting the + logging category "config". [RT #16117] + +2041. [bug] "configure --with-dlz-bdb=yes" produced a bad + set of libraries to be linked. [RT #16129] + +2040. [bug] rbtdb no_references() could trigger an INSIST + failure with --enable-atomic. [RT #16022] + +2039. [func] Check that all buffers passed to the socket code + have been retrieved when the socket event is freed. + [RT #16122] + +2038. [bug] dig/nslookup/host was unlinking from wrong list + when handling errors. [RT #16122] + +2037. [func] When unlinking the first or last element in a list + check that the list head points to the element to + be unlinked. [RT #15959] + +2036. [bug] 'rndc recursing' could cause trigger a REQUIRE. + [RT #16075] + +2035. [func] Make falling back to TCP on UDP refresh failure + optional. Default "try-tcp-refresh yes;" for BIND 8 + compatibility. [RT #16123] + +2034. [bug] gcc: set -fno-strict-aliasing. [RT #16124] + +2033. [bug] We weren't creating multiple client memory contexts + on demand as expected. [RT #16095] + +2032. [bug] Remove a INSIST in query_addadditional2(). [RT #16074] + +2031. [bug] Emit a error message when "rndc refresh" is called on + a non slave/stub zone. [RT # 16073] + +2030. [bug] We were being overly conservative when disabling + openssl engine support. [RT #16030] + +2029. [bug] host printed out the server multiple times when + specified on the command line. [RT #15992] + +2028. [port] linux: socket.c compatibility for old systems. + [RT #16015] + +2027. [port] libbind: Solaris x86 support. [RT #16020] + +2026. [bug] Rate limit the two recursive client exceeded messages. + [RT #16044] + +2025. [func] Update "zone serial unchanged" message. [RT #16026] + +2024. [bug] named emitted spurious "zone serial unchanged" + messages on reload. [RT #16027] + +2023. [bug] "make install" should create ${localstatedir}/run and + ${sysconfdir} if they do not exist. [RT #16033] + +2022. [bug] If dnssec validation is disabled only assert CD if + CD was requested. [RT #16037] + +2021. [bug] dnssec-enable no; triggered a REQUIRE. [RT #16037] + +2020. [bug] rdataset_setadditional() could leak memory. [RT #16034] + +2019. [tuning] Reduce the amount of work performed per quantum + when cleaning the cache. [RT #15986] + +2018. [bug] Checking if the HMAC MD5 private file was broken. + [RT #15960] + +2017. [bug] allow-query default was not correct. [RT #15946] + +2016. [bug] Return a partial answer if recursion is not + allowed but requested and we had the answer + to the original qname. [RT #15945] + +2015. [cleanup] use-additional-cache is now acache-enable for + consistency. Default acache-enable off in BIND 9.4 + as it requires memory usage to be configured. + It may be enabled by default in BIND 9.5 once we + have more experience with it. + +2014. [func] Statistics about acache now recorded and sent + to log. [RT #15976] + +2013. [bug] Handle unexpected TSIGs on unsigned AXFR/IXFR + responses more gracefully. [RT #15941] + +2012. [func] Don't insert new acache entries if acache is full. + [RT #15970] + +2011. [func] dnssec-signzone can now update the SOA record of + the signed zone, either as an increment or as the + system time(). [RT #15633] + +2010. [placeholder] rt15958 + +2009. [bug] libbind: Coverity fixes. [RT #15808] + +2008. [func] It is now possible to enable/disable DNSSEC + validation from rndc. This is useful for the + mobile hosts where the current connection point + breaks DNSSEC (firewall/proxy). [RT #15592] + + rndc validation newstate [view] + +2007. [func] It is now possible to explicitly enable DNSSEC + validation. default dnssec-validation no; to + be changed to yes in 9.5.0. [RT #15674] + +2006. [security] Allow-query-cache and allow-recursion now default + to the built in acls "localnets" and "localhost". + + This is being done to make caching servers less + attractive as reflective amplifying targets for + spoofed traffic. This still leave authoritative + servers exposed. + + The best fix is for full BCP 38 deployment to + remove spoofed traffic. + +2005. [bug] libbind: Retransmission timeouts should be + based on which attempt it is to the nameserver + and not the nameserver itself. [RT #13548] + +2004. [bug] dns_tsig_sign() could pass a NULL pointer to + dst_context_destroy() when cleaning up after a + error. [RT #15835] + +2003. [bug] libbind: The DNS name/address lookup functions could + occasionally follow a random pointer due to + structures not being completely zeroed. [RT #15806] + +2002. [bug] libbind: tighten the constraints on when + struct addrinfo._ai_pad exists. [RT #15783] + +2001. [func] Check the KSK flag when updating a secure dynamic zone. + New zone option "update-check-ksk yes;". [RT #15817] + +2000. [bug] memmove()/strtol() fix was incomplete. [RT #15812] + +1999. [func] Implement "rrset-order fixed". [RT #13662] + +1998. [bug] Restrict handling of fifos as sockets to just SunOS. + This allows named to connect to entropy gathering + daemons that use fifos instead of sockets. [RT #15840] + +1997. [bug] Named was failing to replace negative cache entries + when a positive one for the type was learnt. + [RT #15818] + +1996. [bug] nsupdate: if a zone has been specified it should + appear in the output of 'show'. [RT #15797] + +1995. [bug] 'host' was reporting multiple "is an alias" messages. + [RT #15702] + +1994. [port] OpenSSL 0.9.8 support. [RT #15694] + +1993. [bug] Log messages, via syslog, were missing the space + after the timestamp if "print-time yes" was specified. + [RT #15844] + +1992. [bug] Not all incoming zone transfer messages included the + view. [RT #15825] + +1991. [cleanup] The configuration data, once read, should be treated + as read only. Expand the use of const to enforce this + at compile time. [RT #15813] + +1990. [bug] libbind: isc's override of broken gettimeofday() + implementations was not always effective. + [RT #15709] + +1989. [bug] win32: don't check the service password when + re-installing. [RT #15882] + +1988. [bug] Remove a bus error from the SHA256/SHA512 support. + [RT #15878] + +1987. [func] DS/DLV SHA256 digest algorithm support. [RT #15608] + +1986. [func] Report when a zone is removed. [RT #15849] + +1985. [protocol] DLV has now been assigned a official type code of + 32769. [RT #15807] + + Note: care should be taken to ensure you upgrade + both named and dnssec-signzone at the same time for + zones with DLV records where named is the master + server for the zone. Also any zones that contain + DLV records should be removed when upgrading a slave + zone. You do not however have to upgrade all + servers for a zone with DLV records simultaneously. + +1984. [func] dig, nslookup and host now advertise a 4096 byte + EDNS UDP buffer size by default. [RT #15855] + +1983. [func] Two new update policies. "selfsub" and "selfwild". + [RT #12895] + +1982. [bug] DNSKEY was being accepted on the parent side of + a delegation. KEY is still accepted there for + RFC 3007 validated updates. [RT #15620] + +1981. [bug] win32: condition.c:wait() could fail to reattain + the mutex lock. + +1980. [func] dnssec-signzone: output the SOA record as the + first record in the signed zone. [RT #15758] + +1979. [port] linux: allow named to drop core after changing + user ids. [RT #15753] + +1978. [port] Handle systems which have a broken recvmsg(). + [RT #15742] + +1977. [bug] Silence noisy log message. [RT #15704] + +1976. [bug] Handle systems with no IPv4 addresses. [RT #15695] + +1975. [bug] libbind: isc_gethexstring() could misparse multi-line + hex strings with comments. [RT #15814] + +1974. [doc] List each of the zone types and associated zone + options separately in the ARM. + +1973. [func] TSIG HMACSHA1, HMACSHA224, HMACSHA256, HMACSHA384 and + HMACSHA512 support. [RT #13606] + +1972. [contrib] DBUS dynamic forwarders integration from + Jason Vas Dias . + +1971. [port] linux: make detection of missing IF_NAMESIZE more + robust. [RT #15443] + +1970. [bug] nsupdate: adjust UDP timeout when falling back to + unsigned SOA query. [RT #15775] + +1969. [bug] win32: the socket code was freeing the socket + structure too early. [RT #15776] + +1968. [bug] Missing lock in resolver.c:validated(). [RT #15739] + +1967. [func] dig/nslookup/host: warn about missing "QR". [RT #15779] + +1966. [bug] Don't set CD when we have fallen back to plain DNS. + [RT #15727] + +1965. [func] Suppress spurious "recusion requested but not + available" warning with 'dig +qr'. [RT #15780]. + +1964. [func] Separate out MX and SRV to CNAME checks. [RT #15723] + +1963. [port] Tru64 4.0E doesn't support send() and recv(). + [RT #15586] + +1962. [bug] Named failed to clear old update-policy when it + was removed. [RT #15491] + +1961. [bug] Check the port and address of responses forwarded + to dispatch. [RT #15474] + +1960. [bug] Update code should set NSEC ttls from SOA MINIMUM. + [RT #15465] + +1959. [func] Control the zeroing of the negative response TTL to + a soa query. Defaults "zero-no-soa-ttl yes;" and + "zero-no-soa-ttl-cache no;". [RT #15460] + +1958. [bug] Named failed to update the zone's secure state + until the zone was reloaded. [RT #15412] + +1957. [bug] Dig mishandled responses to class ANY queries. + [RT #15402] + +1956. [bug] Improve cross compile support, 'gen' is now built + by native compiler. See README for additional + cross compile support information. [RT #15148] + +1955. [bug] Pre-allocate the cache cleaning iterator. [RT #14998] + +1954. [func] Named now falls back to advertising EDNS with a + 512 byte receive buffer if the initial EDNS queries + fail. [RT #14852] + +1953. [func] The maximum EDNS UDP response named will send can + now be set in named.conf (max-udp-size). This is + independent of the advertised receive buffer + (edns-udp-size). [RT #14852] + +1952. [port] hpux: tell the linker to build a runtime link + path "-Wl,+b:". [RT #14816]. + +1951. [security] Drop queries from particular well known ports. + Don't return FORMERR to queries from particular + well known ports. [RT #15636] + +1950. [port] Solaris 2.5.1 and earlier cannot bind() then connect() + a TCP socket. This prevents the source address being + set for TCP connections. [RT #15628] + +1949. [func] Addition memory leakage checks. [RT #15544] + +1948. [bug] If was possible to trigger a REQUIRE failure in + xfrin.c:maybe_free() if named ran out of memory. + [RT #15568] + +1947. [func] It is now possible to configure named to accept + expired RRSIGs. Default "dnssec-accept-expired no;". + Setting "dnssec-accept-expired yes;" leaves named + vulnerable to replay attacks. [RT #14685] + +1946. [bug] resume_dslookup() could trigger a REQUIRE failure + when using forwarders. [RT #15549] + +1945. [cleanup] dnssec-keygen: RSA (RSAMD5) is no longer recommended. + To generate a RSAMD5 key you must explicitly request + RSAMD5. [RT #13780] + +1944. [cleanup] isc_hash_create() does not need a read/write lock. + [RT #15522] + +1943. [bug] Set the loadtime after rolling forward the journal. + [RT #15647] + +1942. [bug] If the name of a DNSKEY match that of one in + trusted-keys do not attempt to validate the DNSKEY + using the parents DS RRset. [RT #15649] + +1941. [bug] ncache_adderesult() should set eresult even if no + rdataset is passed to it. [RT #15642] + +1940. [bug] Fixed a number of error conditions reported by + Coverity. + +1939. [bug] The resolver could dereference a null pointer after + validation if all the queries have timed out. + [RT #15528] + +1938. [bug] The validator was not correctly handling unsecure + negative responses at or below a SEP. [RT #15528] + +1937. [bug] sdlz doesn't handle RRSIG records. [RT #15564] + +1936. [bug] The validator could leak memory. [RT #15544] + +1935. [bug] 'acache' was DO sensitive. [RT #15430] + +1934. [func] Validate pending NS RRsets, in the authority section, + prior to returning them if it can be done without + requiring DNSKEYs to be fetched. [RT #15430] + +1933. [bug] dump_rdataset_raw() had a incorrect INSIST. [RT #15534] + +1932. [bug] hpux: LDFLAGS was getting corrupted. [RT #15530] + +1931. [bug] Per-client mctx could require a huge amount of memory, + particularly for a busy caching server. [RT #15519] + +1930. [port] HPUX: ia64 support. [RT #15473] + +1929. [port] FreeBSD: extend use of PTHREAD_SCOPE_SYSTEM. + +1928. [bug] Race in rbtdb.c:currentversion(). [RT #15517] + +1927. [bug] Access to soanode or nsnode in rbtdb violated the + lock order rule and could cause a dead lock. + [RT# 15518] + +1926. [bug] The Windows installer did not check for empty + passwords. BINDinstall was being installed in + the wrong place. [RT #15483] + +1925. [port] All outer level AC_TRY_RUNs need cross compiling + defaults. [RT #15469] + +1924. [port] libbind: hpux ia64 support. [RT #15473] + +1923. [bug] ns_client_detach() called too early. [RT #15499] + +1922. [bug] check-tool.c:setup_logging() missing call to + dns_log_setcontext(). + +1921. [bug] Client memory contexts were not using internal + malloc. [RT# 15434] + +1920. [bug] The cache rbtdb lock array was too small to + have the desired performance characteristics. + [RT #15454] + +1919. [contrib] queryperf: a set of new features: collecting/printing + response delays, printing intermediate results, and + adjusting query rate for the "target" qps. + +1918. [bug] Memory leak when checking acls. [RT #15391] + +1917. [doc] funcsynopsisinfo wasn't being treated as verbatim + when generating man pages. [RT #15385] + +1916. [func] Integrate contributed IDN code from JPNIC. [RT #15383] + +1915. [bug] dig +ndots was broken. [RT #15215] + +1914. [protocol] DS is required to accept mnemonic algorithms + (RFC 4034). Still emit numeric algorithms for + compatibility with RFC 3658. [RT #15354] + +1913. [func] Integrate contributed DLZ code into named. [RT #11382] + +1912. [port] aix: atomic locking for powerpc. [RT #15020] + +1911. [bug] Update windows socket code. [RT #14965] + +1910. [bug] dig's +sigchase code overhauled. [RT #14933] + +1909. [bug] The DLV code has been re-worked to make no longer + query order sensitive. [RT #14933] + +1908. [func] dig now warns if 'RA' is not set in the answer when + 'RD' was set in the query. host/nslookup skip servers + that fail to set 'RA' when 'RD' is set unless a server + is explicitly set. [RT #15005] + +1907. [func] host/nslookup now continue (default)/fail on SERVFAIL. + [RT #15006] + +1906. [func] dig now has a '-q queryname' and '+showsearch' options. + [RT #15034] + +1905. [bug] Strings returned from cfg_obj_asstring() should be + treated as read-only. The prototype for + cfg_obj_asstring() has been updated to reflect this. + [RT #15256] + +1904. [func] Automatic empty zone creation for D.F.IP6.ARPA and + friends. Note: RFC 1918 zones are not yet covered by + this but are likely to be in a future release. + + New options: empty-server, empty-contact, + empty-zones-enable and disable-empty-zone. + +1903. [func] ISC string copy API. + +1902. [func] Attempt to make the amount of work performed in a + iteration self tuning. The covers nodes clean from + the cache per iteration, nodes written to disk when + rewriting a master file and nodes destroyed per + iteration when destroying a zone or a cache. + [RT #14996] + +1901. [cleanup] Don't add DNSKEY records to the additional section. + +1900. [bug] ixfr-from-differences failed to ensure that the + serial number increased. [RT #15036] + +1899. [func] named-checkconf now validates update-policy entries. + [RT #14963] + +1898. [bug] Extend ISC_SOCKADDR_FORMATSIZE and + ISC_NETADDR_FORMATSIZE to allow for scope details. + +1897. [func] x86 and x86_64 now have separate atomic locking + implementations. + +1896. [bug] Recursive clients soft quota support wasn't working + as expected. [RT #15103] + +1895. [bug] A escaped character is, potentially, converted to + the output character set too early. [RT #14666] + +1894. [doc] Review ARM for BIND 9.4. + +1893. [port] Use uintptr_t if available. [RT #14606] + +1892. [func] Support for SPF rdata type. [RT #15033] + +1891. [port] freebsd: pthread_mutex_init can fail if it runs out + of memory. [RT #14995] + +1890. [func] Raise the UDP receive buffer size to 32k if it is + less than 32k. [RT #14953] + +1889. [port] sunos: non blocking i/o support. [RT #14951] + +1888. [func] Support for IPSECKEY rdata type. [RT #14967] + +1887. [bug] The cache could delete expired records too fast for + clients with a virtual time in the past. [RT #14991] + +1886. [bug] fctx_create() could return success even though it + failed. [RT #14993] + +1885. [func] dig: report the number of extra bytes still left in + the packet after processing all the records. + +1884. [cleanup] dighost.c: move external declarations into . + +1883. [bug] dnssec-signzone, dnssec-keygen: handle negative debug + levels. [RT #14962] + +1882. [func] Limit the number of recursive clients that can be + waiting for a single query () to + resolve. New options clients-per-query and + max-clients-per-query. + +1881. [func] Add a system test for named-checkconf. [RT #14931] + +1880. [func] The lame cache is now done on a + basis as some servers only appear to be lame for + certain query types. [RT #14916] + +1879. [func] "USE INTERNAL MALLOC" is now runtime selectable. + [RT #14892] + +1878. [func] Detect duplicates of UDP queries we are recursing on + and drop them. New stats category "duplicate". + [RT #2471] + +1877. [bug] Fix unreasonably low quantum on call to + dns_rbt_destroy2(). Remove unnecessary unhash_node() + call. [RT #14919] + +1876. [func] Additional memory debugging support to track size + and mctx arguments. [RT #14814] + +1875. [bug] process_dhtkey() was using the wrong memory context + to free some memory. [RT #14890] + +1874. [port] sunos: portability fixes. [RT #14814] + +1873. [port] win32: isc__errno2result() now reports its caller. + [RT #13753] + +1872. [port] win32: Handle ERROR_NETNAME_DELETED. [RT #13753] + +1871. [placeholder] + +1870. [func] Added framework for handling multiple EDNS versions. + [RT #14873] + +1869. [func] dig can now specify the EDNS version when making + a query. [RT #14873] + +1868. [func] edns-udp-size can now be overridden on a per + server basis. [RT #14851] + +1867. [bug] It was possible to trigger a INSIST in + dlv_validatezonekey(). [RT #14846] + +1866. [bug] resolv.conf parse errors were being ignored by + dig/host/nslookup. [RT #14841] + +1865. [bug] Silently ignore nameservers in /etc/resolv.conf with + bad addresses. [RT #14841] + +1864. [bug] Don't try the alternative transfer source if you + got a answer / transfer with the main source + address. [RT #14802] + +1863. [bug] rrset-order "fixed" error messages not complete. + +1862. [func] Add additional zone data constancy checks. + named-checkzone has extended checking of NS, MX and + SRV record and the hosts they reference. + named has extended post zone load checks. + New zone options: check-mx and integrity-check. + [RT #4940] + +1861. [bug] dig could trigger a INSIST on certain malformed + responses. [RT #14801] + +1860. [port] solaris 2.8: hack_shutup_pthreadmutexinit was + incorrectly set. [RT #14775] + +1859. [func] Add support for CH A record. [RT #14695] + +1858. [bug] The flush-zones-on-shutdown option wasn't being + parsed. [RT #14686] + +1857. [bug] named could trigger a INSIST() if reconfigured / + reloaded too fast. [RT #14673] + +1856. [doc] Switch Docbook toolchain from DSSSL to XSL. + [RT #11398] + +1855. [bug] ixfr-from-differences was failing to detect changes + of ttl due to dns_diff_subtract() was ignoring the ttl + of records. [RT #14616] + +1854. [bug] lwres also needs to know the print format for + (long long). [RT #13754] + +1853. [bug] Rework how DLV interacts with proveunsecure(). + [RT #13605] + +1852. [cleanup] Remove last vestiges of dnssec-signkey and + dnssec-makekeyset (removed from Makefile years ago). + +1851. [doc] Doxygen comment markup. [RT #11398] + +1850. [bug] Memory leak in lwres_getipnodebyaddr(). [RT #14591] + +1849. [doc] All forms of the man pages (docbook, man, html) should + have consistent copyright dates. + +1848. [bug] Improve SMF integration. [RT #13238] + +1847. [bug] isc_ondestroy_init() is called too late in + dns_rbtdb_create()/dns_rbtdb64_create(). + [RT #13661] + +1846. [contrib] query-loc-0.3.0 from Stephane Bortzmeyer + . + +1845. [bug] Improve error reporting to distinguish between + accept()/fcntl() and socket()/fcntl() errors. + [RT #13745] + +1844. [bug] inet_pton() accepted more that 4 hexadecimal digits + for each 16 bit piece of the IPv6 address. The text + representation of a IPv6 address has been tightened + to disallow this (draft-ietf-ipv6-addr-arch-v4-02.txt). + [RT #5662] + +1843. [cleanup] CINCLUDES takes precedence over CFLAGS. This helps + when CFLAGS contains "-I /usr/local/include" + resulting in old header files being used. + +1842. [port] cmsg_len() could produce incorrect results on + some platform. [RT #13744] + +1841. [bug] "dig +nssearch" now makes a recursive query to + find the list of nameservers to query. [RT #13694] + +1840. [func] dnssec-signzone can now randomize signature end times + (dnssec-signzone -j jitter). [RT #13609] + +1839. [bug] was not being installed. + +1838. [cleanup] Don't allow Linux capabilities to be inherited. + [RT #13707] + +1837. [bug] Compile time option ISC_FACILITY was not effective + for 'named -u '. [RT #13714] + +1836. [cleanup] Silence compiler warnings in hash_test.c. + +1835. [bug] Update dnssec-signzone's usage message. [RT #13657] + +1834. [bug] Bad memset in rdata_test.c. [RT #13658] + +1833. [bug] Race condition in isc_mutex_lock_profile(). [RT #13660] + +1832. [bug] named fails to return BADKEY on unknown TSIG algorithm. + [RT #13620] + +1831. [doc] Update named-checkzone documentation. [RT#13604] + +1830. [bug] adb lame cache has sence of test reversed. [RT #13600] + +1829. [bug] win32: "pid-file none;" broken. [RT #13563] + +1828. [bug] isc_rwlock_init() failed to properly cleanup if it + encountered a error. [RT #13549] + +1827. [bug] host: update usage message for '-a'. [RT #37116] + +1826. [bug] Missing DESTROYLOCK() in isc_mem_createx() on out + of memory error. [RT #13537] + +1825. [bug] Missing UNLOCK() on out of memory error from in + rbtdb.c:subtractrdataset(). [RT #13519] + +1824. [bug] Memory leak on dns_zone_setdbtype() failure. + [RT #13510] + +1823. [bug] Wrong macro used to check for point to point interface. + [RT#13418] + +1822. [bug] check-names test for RT was reversed. [RT #13382] + +1821. [placeholder] + +1820. [bug] Gracefully handle acl loops. [RT #13659] + +1819. [bug] The validator needed to check both the algorithm and + digest types of the DS to determine if it could be + used to introduce a secure zone. [RT #13593] + +1818. [bug] 'named-checkconf -z' triggered an INSIST. [RT #13599] + +1817. [func] Add support for additional zone file formats for + improving loading performance. The masterfile-format + option in named.conf can be used to specify a + non-default format. A separate command + named-compilezone was provided to generate zone files + in the new format. Additionally, the -I and -O options + for dnssec-signzone specify the input and output + formats. + +1816. [port] UnixWare: failed to compile lib/isc/unix/net.c. + [RT #13597] + +1815. [bug] nsupdate triggered a REQUIRE if the server was set + without also setting the zone and it encountered + a CNAME and was using TSIG. [RT #13086] + +1814. [func] UNIX domain controls are now supported. + +1813. [func] Restructured the data locking framework using + architecture dependent atomic operations (when + available), improving response performance on + multi-processor machines significantly. + x86, x86_64, alpha, powerpc, and mips are currently + supported. + +1812. [port] win32: IN6_IS_ADDR_UNSPECIFIED macro is incorrect. + [RT #13453] + +1811. [func] Preserve the case of domain names in rdata during + zone transfers. [RT #13547] + +1810. [bug] configure, lib/bind/configure make different default + decisions about whether to do a threaded build. + [RT #13212] + +1809. [bug] "make distclean" failed for libbind if the platform + is not supported. + +1808. [bug] zone.c:notify_zone() contained a race condition, + zone->db could change underneath it. [RT #13511] + +1807. [bug] When forwarding (forward only) set the active domain + from the forward zone name. [RT #13526] + +1806. [bug] The resolver returned the wrong result when a CNAME / + DNAME was encountered when fetching glue from a + secure namespace. [RT #13501] + +1805. [bug] Pending status was not being cleared when DLV was + active. [RT #13501] + +1804. [bug] Ensure that if we are queried for glue that it fits + in the additional section or TC is set to tell the + client to retry using TCP. [RT #10114] + +1803. [bug] dnssec-signzone sometimes failed to remove old + RRSIGs. [RT #13483] + +1802. [bug] Handle connection resets better. [RT #11280] + +1801. [func] Report differences between hints and real NS rrset + and associated address records. + +1800. [bug] Changes #1719 allowed a INSIST to be triggered. + [RT #13428] + +1799. [bug] 'rndc flushname' failed to flush negative cache + entries. [RT #13438] + +1798. [func] The server syntax has been extended to support a + range of servers. [RT #11132] + +1797. [func] named-checkconf now check acls to verify that they + only refer to existing acls. [RT #13101] + +1796. [func] "rndc freeze/thaw" now freezes/thaws all zones. + +1795. [bug] "rndc dumpdb" was not fully documented. Minor + formating issues with "rndc dumpdb -all". [RT #13396] + +1794. [func] Named and named-checkzone can now both check for + non-terminal wildcard records. + +1793. [func] Extend adjusting TTL warning messages. [RT #13378] + +1792. [func] New zone option "notify-delay". Specify a minimum + delay between sets of NOTIFY messages. + +1791. [bug] 'host -t a' still printed out AAAA and MX records. + [RT #13230] + +1790. [cleanup] Move lib/dns/sec/dst up into lib/dns. This should + allow parallel make to succeed. + +1789. [bug] Prerequisite test for tkey and dnssec could fail + with "configure --with-libtool". + +1788. [bug] libbind9.la/libbind9.so needs to link against + libisccfg.la/libisccfg.so. + +1787. [port] HPUX: both "cc" and "gcc" need -Wl,+vnocompatwarnings. + +1786. [port] AIX: libt_api needs to be taught to look for + T_testlist in the main executable (--with-libtool). + [RT #13239] + +1785. [bug] libbind9.la/libbind9.so needs to link against + libisc.la/libisc.so. + +1784. [cleanup] "libtool -allow-undefined" is the default. + Leave hooks in configure to allow it to be set + if needed in the future. + +1783. [cleanup] We only need one copy of libtool.m4, ltmain.sh in the + source tree. + +1782. [port] OSX: --with-libtool + --enable-libbind broke on + __evOptMonoTime. [RT #13219] + +1781. [port] FreeBSD 5.3: set PTHREAD_SCOPE_SYSTEM. [RT #12810] + +1780. [bug] Update libtool to 1.5.10. + +1779. [port] OSF 5.1: libtool didn't handle -pthread correctly. + +1778. [port] HUX 11.11: fix broken IN6ADDR_ANY_INIT and + IN6ADDR_LOOPBACK_INIT macros. + +1777. [port] OSF 5.1: fix broken IN6ADDR_ANY_INIT and + IN6ADDR_LOOPBACK_INIT macros. + +1776. [port] Solaris 2.9: fix broken IN6ADDR_ANY_INIT and + IN6ADDR_LOOPBACK_INIT macros. + +1775. [bug] Only compile getnetent_r.c when threaded. [RT #13205] + +1774. [port] Aix: Silence compiler warnings / build failures. + [RT #13154] + +1773. [bug] Fast retry on host / net unreachable. [RT #13153] + +1772. [placeholder] + +1771. [placeholder] + +1770. [bug] named-checkconf failed to report missing a missing + file clause for rbt{64} master/hint zones. [RT#13009] + +1769. [port] win32: change compiler flags /MTd ==> /MDd, + /MT ==> /MD. + +1768. [bug] nsecnoexistnodata() could be called with a non-NSEC + rdataset. [RT #12907] + +1767. [port] Builds on IPv6 platforms without IPv6 Advanced API + support for (struct in6_pktinfo) failed. [RT #13077] + +1766. [bug] Update the master file timestamp on successful refresh + as well as the journal's timestamp. [RT# 13062] + +1765. [bug] configure --with-openssl=auto failed. [RT #12937] + +1764. [bug] dns_zone_replacedb failed to emit a error message + if there was no SOA record in the replacement db. + [RT #13016] + +1763. [func] Perform sanity checks on NS records which refer to + 'in zone' names. [RT #13002] + +1762. [bug] isc_interfaceiter_create() could return ISC_R_SUCCESS + even when it failed. [RT #12995] + +1761. [bug] 'rndc dumpdb' didn't report unassociated entries. + [RT #12971] + +1760. [bug] Host / net unreachable was not penalising rtt + estimates. [RT #12970] + +1759. [bug] Named failed to startup if the OS supported IPv6 + but had no IPv6 interfaces configured. [RT #12942] + +1758. [func] Don't send notify messages to self. [RT #12933] + +1757. [func] host now can turn on memory debugging flags with '-m'. + +1756. [func] named-checkconf now checks the logging configuration. + [RT #12352] + +1755. [func] allow-update is now settable at the options / view + level. [RT #6636] + +1754. [bug] We weren't always attempting to query the parent + server for the DS records at the zone cut. + [RT #12774] + +1753. [bug] Don't serve a slave zone which has no NS records. + [RT #12894] + +1752. [port] Move isc_app_start() to after ns_os_daemonise() + as some fork() implementations unblock the signals + that are blocked by isc_app_start(). [RT #12810] + +1751. [bug] --enable-getifaddrs failed under linux. [RT #12867] + +1750. [port] lib/bind/make/rules.in:subdirs was not bash friendly. + [RT #12864] + +1749. [bug] 'check-names response ignore;' failed to ignore. + [RT #12866] + +1748. [func] dig now returns the byte count for axfr/ixfr. + +1747. [bug] BIND 8 compatibility: named/named-checkconf failed + to parse "host-statistics-max" in named.conf. + +1746. [func] Make public the function to read a key file, + dst_key_read_public(). [RT #12450] + +1745. [bug] Dig/host/nslookup accept replies from link locals + regardless of scope if no scope was specified when + query was sent. [RT #12745] + +1744. [bug] If tuple2msgname() failed to convert a tuple to + a name a REQUIRE could be triggered. [RT #12796] + +1743. [bug] If isc_taskmgr_create() was not able to create the + requested number of worker threads then destruction + of the manager would trigger an INSIST() failure. + [RT #12790] + +1742. [bug] Deleting all records at a node then adding a + previously existing record, in a single UPDATE + transaction, failed to leave / regenerate the + associated RRSIG records. [RT #12788] + +1741. [bug] Deleting all records at a node in a secure zone + using a update-policy grant failed. [RT #12787] + +1740. [bug] Replace rbt's hash algorithm as it performed badly + with certain zones. [RT #12729] + + NOTE: a hash context now needs to be established + via isc_hash_create() if the application was not + already doing this. + +1739. [bug] dns_rbt_deletetree() could incorrectly return + ISC_R_QUOTA. [RT #12695] + +1738. [bug] Enable overrun checking by default. [RT #12695] + +1737. [bug] named failed if more than 16 masters were specified. + [RT #12627] + +1736. [bug] dst_key_fromnamedfile() could fail to read a + public key. [RT #12687] + +1735. [bug] 'dig +sigtrace' could die with a REQUIRE failure. + [RE #12688] + +1734. [cleanup] 'rndc-confgen -a -t' remove extra '/' in path. + [RT #12588] + +1733. [bug] Return non-zero exit status on initial load failure. + [RT #12658] + +1732. [bug] 'rrset-order name "*"' wasn't being applied to ".". + [RT #12467] + +1731. [port] darwin: relax version test in ifconfig.sh. + [RT #12581] + +1730. [port] Determine the length type used by the socket API. + [RT #12581] + +1729. [func] Improve check-names error messages. + +1728. [doc] Update check-names documentation. + +1727. [bug] named-checkzone: check-names support didn't match + documentation. + +1726. [port] aix5: add support for aix5. + +1725. [port] linux: update error message on interaction of threads, + capabilities and setuid support (named -u). [RT #12541] + +1724. [bug] Look for DNSKEY records with "dig +sigtrace". + [RT #12557] + +1723. [cleanup] Silence compiler warnings from t_tasks.c. [RT #12493] + +1722. [bug] Don't commit the journal on malformed ixfr streams. + [RT #12519] + +1721. [bug] Error message from the journal processing were not + always identifying the relevant journal. [RT #12519] + +1720. [bug] 'dig +chase' did not terminate on a RFC 2308 Type 1 + negative response. [RT #12506] + +1719. [bug] named was not correctly caching a RFC 2308 Type 1 + negative response. [RT #12506] + +1718. [bug] nsupdate was not handling RFC 2308 Type 3 negative + responses when looking for the zone / master server. + [RT #12506] + +1717. [port] solaris: ifconfig.sh did not support Solaris 10. + "ifconfig.sh down" didn't work for Solaris 9. + +1716. [doc] named.conf(5) was being installed in the wrong + location. [RT# 12441] + +1715. [func] 'dig +trace' now randomly selects the next servers + to try. Report if there is a bad delegation. + +1714. [bug] dig/host/nslookup were only trying the first + address when a nameserver was specified by name. + [RT #12286] + +1713. [port] linux: extend capset failure message to say: + please ensure that the capset kernel module is + loaded. see insmod(8) + +1712. [bug] Missing FULLCHECK for "trusted-key" in dig. + +1711. [func] 'rndc unfreeze' has been deprecated by 'rndc thaw'. + +1710. [func] 'rndc notify zone [class [view]]' resend the NOTIFY + messages for the specified zone. [RT #9479] + +1709. [port] solaris: add SMF support from Sun. + +1708. [cleanup] Replaced dns_fullname_hash() with dns_name_fullhash() + for conformance to the name space convention. Binary + backward compatibility to the old function name is + provided. [RT #12376] + +1707. [contrib] sdb/ldap updated to version 1.0-beta. + +1706. [bug] 'rndc stop' failed to cause zones to be flushed + sometimes. [RT #12328] + +1705. [func] Allow the journal's name to be changed via named.conf. + +1704. [port] lwres needed a snprintf() implementation for + platforms without snprintf(). Add missing + "#include ". [RT #12321] + +1703. [bug] named would loop sending NOTIFY messages when it + failed to receive a response. [RT #12322] + +1702. [bug] also-notify should not be applied to built in zones. + [RT #12323] + +1701. [doc] A minimal named.conf man page. + +1700. [func] nslookup is no longer to be treated as deprecated. + Remove "deprecated" warning message. Add man page. + +1699. [bug] dnssec-signzone can generate "not exact" errors + when resigning. [RT #12281] + +1698. [doc] Use reserved IPv6 documentation prefix. + +1697. [bug] xxx-source{,-v6} was not effective when it + specified one of listening addresses and a + different port than the listening port. [RT #12257] + +1696. [bug] dnssec-signzone failed to clean out nodes that + consisted of only NSEC and RRSIG records. + [RT #12154] + +1695. [bug] DS records when forwarding require special handling. + [RT #12133] + +1694. [bug] Report if the builtin views of "_default" / "_bind" + are defined in named.conf. [RT #12023] + +1693. [bug] max-journal-size was not effective for master zones + with ixfr-from-differences set. [RT# 12024] + +1692. [bug] Don't set -I, -L and -R flags when libcrypto is in + /usr/lib. [RT #11971] + +1691. [bug] sdb's attachversion was not complete. [RT #11990] + +1690. [bug] Delay detaching view from the client until UPDATE + processing completes when shutting down. [RT #11714] + +1689. [bug] DNS_NAME_TOREGION() and DNS_NAME_SPLIT() macros + contained gratuitous semicolons. [RT #11707] + +1688. [bug] LDFLAGS was not supported. + +1687. [bug] Race condition in dispatch. [RT #10272] + +1686. [bug] Named sent a extraneous NOTIFY when it received a + redundant UPDATE request. [RT #11943] + +1685. [bug] Change #1679 loop tests weren't quite right. + +1684. [func] ixfr-from-differences now takes master and slave in + addition to yes and no at the options and view levels. + +1683. [bug] dig +sigchase could leak memory. [RT #11445] + +1682. [port] Update configure test for (long long) printf format. + [RT #5066] + +1681. [bug] Only set SO_REUSEADDR when a port is specified in + isc_socket_bind(). [RT #11742] + +1680. [func] rndc: the source address can now be specified. + +1679. [bug] When there was a single nameserver with multiple + addresses for a zone not all addresses were tried. + [RT #11706] + +1678. [bug] RRSIG should use TYPEXXXXX for unknown types. + +1677. [bug] dig: +aaonly didn't work, +aaflag undocumented. + +1676. [func] New option "allow-query-cache". This lets + allow-query be used to specify the default zone + access level rather than having to have every + zone override the global value. allow-query-cache + can be set at both the options and view levels. + If allow-query-cache is not set allow-query applies. + +1675. [bug] named would sometimes add extra NSEC records to + the authority section. + +1674. [port] linux: increase buffer size used to scan + /proc/net/if_inet6. + +1673. [port] linux: issue a error messages if IPv6 interface + scans fails. + +1672. [cleanup] Tests which only function in a threaded build + now return R:THREADONLY (rather than R:UNTESTED) + in a non-threaded build. + +1671. [contrib] queryperf: add NAPTR to the list of known types. + +1670. [func] Log UPDATE requests to slave zones without an acl as + "disabled" at debug level 3. [RT# 11657] + +1669. [placeholder] + +1668. [bug] DIG_SIGCHASE was making bin/dig/host dump core. + +1667. [port] linux: not all versions have IF_NAMESIZE. + +1666. [bug] The optional port on hostnames in dual-stack-servers + was being ignored. + +1665. [func] rndc now allows addresses to be set in the + server clauses. + +1664. [bug] nsupdate needed KEY for SIG(0), not DNSKEY. + +1663. [func] Look for OpenSSL by default. + +1662. [bug] Change #1658 failed to change one use of 'type' + to 'keytype'. + +1661. [bug] Restore dns_name_concatenate() call in + adb.c:set_target(). [RT #11582] + +1660. [bug] win32: connection_reset_fix() was being called + unconditionally. [RT #11595] + +1659. [cleanup] Cleanup some messages that were referring to KEY vs + DNSKEY, NXT vs NSEC and SIG vs RRSIG. + +1658. [func] Update dnssec-keygen to default to KEY for HMAC-MD5 + and DH. Tighten which options apply to KEY and + DNSKEY records. + +1657. [doc] ARM: document query log output. + +1656. [doc] Update DNSSEC description in ARM to cover DS, NSEC + DNSKEY and RRSIG. [RT #11542] + +1655. [bug] Logging multiple versions w/o a size was broken. + [RT #11446] + +1654. [bug] isc_result_totext() contained array bounds read + error. + +1653. [func] Add key type checking to dst_key_fromfilename(), + DST_TYPE_KEY should be used to read TSIG, TKEY and + SIG(0) keys. + +1652. [bug] TKEY still uses KEY. + +1651. [bug] dig: process multiple dash options. + +1650. [bug] dig, nslookup: flush standard out after each command. + +1649. [bug] Silence "unexpected non-minimal diff" message. + [RT #11206] + +1648. [func] Update dnssec-lookaside named.conf syntax to support + multiple dnssec-lookaside namespaces (not yet + implemented). + +1647. [bug] It was possible trigger a INSIST when chasing a DS + record that required walking back over a empty node. + [RT #11445] + +1646. [bug] win32: logging file versions didn't work with + non-UNC filenames. [RT#11486] + +1645. [bug] named could trigger a REQUIRE failure if multiple + masters with keys are specified. + +1644. [bug] Update the journal modification time after a + successful refresh query. [RT #11436] + +1643. [bug] dns_db_closeversion() could leak memory / node + references. [RT #11163] + +1642. [port] Support OpenSSL implementations which don't have + DSA support. [RT #11360] + +1641. [bug] Update the check-names description in ARM. [RT #11389] + +1640. [bug] win32: isc_socket_cancel(ISC_SOCKCANCEL_ACCEPT) was + incorrectly closing the socket. [RT #11291] + +1639. [func] Initial dlv system test. + +1638. [bug] "ixfr-from-differences" could generate a REQUIRE + failure if the journal open failed. [RT #11347] + +1637. [bug] Node reference leak on error in addnoqname(). + +1636. [bug] The dump done callback could get ISC_R_SUCCESS even if + a error had occurred. The database version no longer + matched the version of the database that was dumped. + +1635. [bug] Memory leak on error in query_addds(). + +1634. [bug] named didn't supply a useful error message when it + detected duplicate views. [RT #11208] + +1633. [bug] named should return NOTIMP to update requests to a + slaves without a allow-update-forwarding acl specified. + [RT #11331] + +1632. [bug] nsupdate failed to send prerequisite only UPDATE + messages. [RT #11288] + +1631. [bug] dns_journal_compact() could sometimes corrupt the + journal. [RT #11124] + +1630. [contrib] queryperf: add support for IPv6 transport. + +1629. [func] dig now supports IPv6 scoped addresses with the + extended format in the local-server part. [RT #8753] + +1628. [bug] Typo in Compaq Trucluster support. [RT# 11264] + +1627. [bug] win32: sockets were not being closed when the + last external reference was removed. [RT# 11179] + +1626. [bug] --enable-getifaddrs was broken. [RT#11259] + +1625. [bug] named failed to load/transfer RFC2535 signed zones + which contained CNAMES. [RT# 11237] + +1624. [bug] zonemgr_putio() call should be locked. [RT# 11163] + +1623. [bug] A serial number of zero was being displayed in the + "sending notifies" log message when also-notify was + used. [RT #11177] + +1622. [func] probe the system to see if IPV6_(RECV)PKTINFO is + available, and suppress wildcard binding if not. + +1621. [bug] match-destinations did not work for IPv6 TCP queries. + [RT# 11156] + +1620. [func] When loading a zone report if it is signed. [RT #11149] + +1619. [bug] Missing ISC_LIST_UNLINK in end_reserved_dispatches(). + [RT# 11118] + +1618. [bug] Fencepost errors in dns_name_ishostname() and + dns_name_ismailbox() could trigger a INSIST(). + +1617. [port] win32: VC++ 6.0 support. + +1616. [compat] Ensure that named's version is visible in the core + dump. [RT #11127] + +1615. [port] Define ISC_SOCKADDR_LEN_T based on _BSD_SOCKLEN_T_ if + it is defined. + +1614. [port] win32: silence resource limit messages. [RT# 11101] + +1613. [bug] Builds would fail on machines w/o a if_nametoindex(). + Missing #ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX/#endif. + [RT #11119] + +1612. [bug] check-names at the option/view level could trigger + an INSIST. [RT# 11116] + +1611. [bug] solaris: IPv6 interface scanning failed to cope with + no active IPv6 interfaces. + +1610. [bug] On dual stack machines "dig -b" failed to set the + address type to be looked up with "@server". + [RT #11069] + +1609. [func] dig now has support to chase DNSSEC signature chains. + Requires -DDIG_SIGCHASE=1 to be set in STD_CDEFINES. + + DNSSEC validation code in dig coded by Olivier Courtay + (olivier.courtay@irisa.fr) for the IDsA project + (http://idsa.irisa.fr). + +1608. [func] dig and host now accept -4/-6 to select IP transport + to use when making queries. + +1607. [bug] dig, host and nslookup were still using random() + to generate query ids. [RT# 11013] + +1606. [bug] DLV insecurity proof was failing. + +1605. [func] New dns_db_find() option DNS_DBFIND_COVERINGNSEC. + +1604. [bug] A xfrout_ctx_create() failure would result in + xfrout_ctx_destroy() being called with a + partially initialized structure. + +1603. [bug] nsupdate: set interactive based on isatty(). + [RT# 10929] + +1602. [bug] Logging to a file failed unless a size was specified. + [RT# 10925] + +1601. [bug] Silence spurious warning 'both "recursion no;" and + "allow-recursion" active' warning from view "_bind". + [RT# 10920] + +1600. [bug] Duplicate zone pre-load checks were not case + insensitive. + +1599. [bug] Fix memory leak on error path when checking named.conf. + +1598. [func] Specify that certain parts of the namespace must + be secure (dnssec-must-be-secure). + +1597. [func] Allow notify-source and query-source to be specified + on a per server basis similar to transfer-source. + [RT #6496] + +1596. [func] Accept 'notify-source' style syntax for query-source. + +1595. [func] New notify type 'master-only'. Enable notify for + master zones only. + +1594. [bug] 'rndc dumpdb' could prevent named from answering + queries while the dump was in progress. [RT #10565] + +1593. [bug] rndc should return "unknown command" to unknown + commands. [RT# 10642] + +1592. [bug] configure_view() could leak a dispatch. [RT# 10675] + +1591. [bug] libbind: updated to BIND 8.4.5. + +1590. [port] netbsd: update thread support. + +1589. [func] DNSSEC lookaside validation. + +1588. [bug] win32: TCP sockets could become blocked. [RT #10115] + +1587. [bug] dns_message_settsigkey() failed to clear existing key. + [RT #10590] + +1586. [func] "check-names" is now implemented. + +1585. [placeholder] + +1584. [bug] "make test" failed with a read only source tree. + [RT #10461] + +1583. [bug] Records add via UPDATE failed to get the correct trust + level. [RT #10452] + +1582. [bug] rrset-order failed to work on RRsets with more + than 32 elements. [RT #10381] + +1581. [func] Disable DNSSEC support by default. To enable + DNSSEC specify "dnssec-enable yes;" in named.conf. + +1580. [bug] Zone destruction on final detach takes a long time. + [RT #3746] + +1579. [bug] Multiple task managers could not be created. + +1578. [bug] Don't use CLASS E IPv4 addresses when resolving. + [RT #10346] + +1577. [bug] Use isc_uint32_t in ultrasparc optimizer bug + workaround code. [RT #10331] + +1576. [bug] Race condition in dns_dispatch_addresponse(). + [RT# 10272] + +1575. [func] Log TSIG name on TSIG verify failure. [RT #4404] + +1574. [bug] Don't attempt to open the controls socket(s) when + running tests. [RT #9091] + +1573. [port] linux: update to libtool 1.5.2 so that + "make install DESTDIR=/xx" works with + "configure --with-libtool". [RT #9941] + +1572. [bug] nsupdate: sign the soa query to find the enclosing + zone if the server is specified. [RT #10148] + +1571. [bug] rbt:hash_node() could fail leaving the hash table + in an inconsistent state. [RT #10208] + +1570. [bug] nsupdate failed to handle classes other than IN. + New keyword 'class' which sets the default class. + [RT #10202] + +1569. [func] nsupdate new command 'answer' which displays the + complete answer message to the last update. + +1568. [bug] nsupdate now reports that the update failed in + interactive mode. [RT# 10236] + +1567. [maint] B.ROOT-SERVERS.NET is now 192.228.79.201. + +1566. [port] Support for the cmsg framework on Solaris and HP/UX. + This also solved the problem that match-destinations + for IPv6 addresses did not work on these systems. + [RT #10221] + +1565. [bug] CD flag should be copied to outgoing queries unless + the query is under a secure entry point in which case + CD should be set. + +1564. [func] Attempt to provide a fallback entropy source to be + used if named is running chrooted and named is unable + to open entropy source within the chroot area. + [RT #10133] + +1563. [bug] Gracefully fail when unable to obtain neither an IPv4 + nor an IPv6 dispatch. [RT #10230] + +1562. [bug] isc_socket_create() and isc_socket_accept() could + leak memory under error conditions. [RT #10230] + +1561. [bug] It was possible to release the same name twice if + named ran out of memory. [RT #10197] + +1560. [port] FreeBSD: work around FreeBSD 5.2 mapping EAI_NODATA + and EAI_NONAME to the same value. + +1559. [port] named should ignore SIGFSZ. + +1558. [func] New DNSSEC 'disable-algorithms'. Support entry into + child zones for which we don't have a supported + algorithm. Such child zones are treated as unsigned. + +1557. [func] Implement missing DNSSEC tests for + * NOQNAME proof with wildcard answers. + * NOWILDARD proof with NXDOMAIN. + Cache and return NOQNAME with wildcard answers. + +1556. [bug] nsupdate now treats all names as fully qualified. + [RT #6427] + +1555. [func] 'rrset-order cyclic' no longer has a random starting + point per query. [RT #7572] + +1554. [bug] dig, host, nslookup failed when no nameservers + were specified in /etc/resolv.conf. [RT #8232] + +1553. [bug] The windows socket code could stop accepting + connections. [RT#10115] + +1552. [bug] Accept NOTIFY requests from mapped masters if + matched-mapped is set. [RT #10049] + +1551. [port] Open "/dev/null" before calling chroot(). + +1550. [port] Call tzset(), if available, before calling chroot(). + +1549. [func] named-checkzone can now write out the zone contents + in a easily parsable format (-D and -o). + +1548. [bug] When parsing APL records it was possible to silently + accept out of range ADDRESSFAMILY values. [RT# 9979] + +1547. [bug] Named wasted memory recording duplicate lame zone + entries. [RT #9341] + +1546. [bug] We were rejecting valid secure CNAME to negative + answers. + +1545. [bug] It was possible to leak memory if named was unable to + bind to the specified transfer source and TSIG was + being used. [RT #10120] + +1544. [bug] Named would logged a single entry to a file despite it + being over the specified size limit. + +1543. [bug] Logging using "versions unlimited" did not work. + +1542. [placeholder] + +1541. [func] NSEC now uses new bitmap format. + +1540. [bug] "rndc reload " was silently accepted. + [RT #8934] + +1539. [bug] Open UDP sockets for notify-source and transfer-source + that use reserved ports at startup. [RT #9475] + +1538. [placeholder] rt9997 + +1537. [func] New option "querylog". If set specify whether query + logging is to be enabled or disabled at startup. + +1536. [bug] Windows socket code failed to log a error description + when returning ISC_R_UNEXPECTED. [RT #9998] + +1535. [placeholder] + +1534. [bug] Race condition when priming cache. [RT# 9940] + +1533. [func] Warn if both "recursion no;" and "allow-recursion" + are active. [RT# 4389] + +1532. [port] netbsd: the configure test for + requires . + +1531. [port] AIX more libtool fixes. + +1530. [bug] It was possible to trigger a INSIST() failure if a + slave master file was removed at just the correct + moment. [RT #9462] + +1529. [bug] "notify explicit;" failed to log that NOTIFY messages + were being sent for the zone. [RT# 9442] + +1528. [cleanup] Simplify some dns_name_ functions based on the + deprecation of bitstring labels. + +1527. [cleanup] Reduce the number of gettimeofday() calls without + losing necessary timer granularity. + +1526. [func] Implemented "additional section caching (or acache)", + an internal cache framework for additional section + content to improve response performance. Several + configuration options were provided to control the + behavior. + +1525. [bug] dns_cache_create() could trigger a REQUIRE + failure in isc_mem_put() during error cleanup. + [RT# 9360] + +1524. [port] AIX needs to be able to resolve all symbols when + creating shared libraries (--with-libtool). + +1523. [bug] Fix race condition in rbtdb. [RT# 9189] + +1522. [bug] dns_db_findnode() relax the requirements on 'name'. + [RT# 9286] + +1521. [bug] dns_view_createresolver() failed to check the + result from isc_mem_create(). [RT# 9294] + +1520. [protocol] Add SSHFP (SSH Finger Print) type. + +1519. [bug] dnssec-signzone:nsec_setbit() computed the wrong + length of the new bitmap. + +1518. [bug] dns_nsec_buildrdata(), and hence dns_nsec_build(), + contained a off-by-one error when working out the + number of octets in the bitmap. + +1517. [port] Support for IPv6 interface scanning on HP/UX and + TrueUNIX 5.1. + +1516. [func] Roll the DNSSEC types to RRSIG, NSEC and DNSKEY. + +1515. [func] Allow transfer source to be set in a server statement. + [RT #6496] + +1514. [bug] named: isc_hash_destroy() was being called too early. + [RT #9160] + +1513. [doc] Add "US" to root-delegation-only exclude list. + +1512. [bug] Extend the delegation-only logging to return query + type, class and responding nameserver. + +1511. [bug] delegation-only was generating false positives + on negative answers from sub-zones. + +1510. [func] New view option "root-delegation-only". Apply + delegation-only check to all TLDs and root. + Note there are some TLDs that are NOT delegation + only (e.g. DE, LV, US and MUSEUM) these can be excluded + from the checks by using exclude. + + root-delegation-only exclude { + "DE"; "LV"; "US"; "MUSEUM"; + }; + +1509. [bug] Hint zones should accept delegation-only. Forward + zone should not accept delegation-only. + +1508. [bug] Don't apply delegation-only checks to answers from + forwarders. + +1507. [bug] Handle BIND 8 style returns to NS queries to parents + when making delegation-only checks. + +1506. [bug] Wrong return type for dns_view_isdelegationonly(). + +1505. [bug] Uninitialized rdataset in sdb. [RT #8750] + +1504. [func] New zone type "delegation-only". + +1503. [port] win32: install libeay32.dll outside of system32. + +1502. [bug] nsupdate: adjust timeouts for UPDATE requests over TCP. + +1501. [func] Allow TCP queue length to be specified via + named.conf, tcp-listen-queue. + +1500. [bug] host failed to lookup MX records. Also look up + AAAA records. + +1499. [bug] isc_random need to be seeded better if arc4random() + is not used. + +1498. [port] bsdos: 5.x support. + +1497. [placeholder] + +1496. [port] test for pthread_attr_setstacksize(). + +1495. [cleanup] Replace hash functions with universal hash. + +1494. [security] Turn on RSA BLINDING as a precaution. + +1493. [placeholder] + +1492. [cleanup] Preserve rwlock quota context when upgrading / + downgrading. [RT #5599] + +1491. [bug] dns_master_dump*() would produce extraneous $ORIGIN + lines. [RT #6206] + +1490. [bug] Accept reading state as well as working state in + ns_client_next(). [RT #6813] + +1489. [compat] Treat 'allow-update' on slave zones as a warning. + [RT #3469] + +1488. [bug] Don't override trust levels for glue addresses. + [RT #5764] + +1487. [bug] A REQUIRE() failure could be triggered if a zone was + queued for transfer and the zone was then removed. + [RT #6189] + +1486. [bug] isc_print_snprintf() '%%' consumed one too many format + characters. [RT# 8230] + +1485. [bug] gen failed to handle high type values. [RT #6225] + +1484. [bug] The number of records reported after a AXFR was wrong. + [RT #6229] + +1483. [bug] dig axfr failed if the message id in the answer failed + to match that in the request. Only the id in the first + message is required to match. [RT #8138] + +1482. [bug] named could fail to start if the kernel supports + IPv6 but no interfaces are configured. Similarly + for IPv4. [RT #6229] + +1481. [bug] Refresh and stub queries failed to use masters keys + if specified. [RT #7391] + +1480. [bug] Provide replay protection for rndc commands. Full + replay protection requires both rndc and named to + be updated. Partial replay protection (limited + exposure after restart) is provided if just named + is updated. + +1479. [bug] cfg_create_tuple() failed to handle out of + memory cleanup. parse_list() would leak memory + on syntax errors. + +1478. [port] ifconfig.sh didn't account for other virtual + interfaces. It now takes a optional argument + to specify the first interface number. [RT #3907] + +1477. [bug] memory leak using stub zones and TSIG. + +1476. [placeholder] + +1475. [port] Probe for old sprintf(). + +1474. [port] Provide strtoul() and memmove() for platforms + without them. + +1473. [bug] create_map() and create_string() failed to handle out + of memory cleanup. [RT #6813] + +1472. [contrib] idnkit-1.0 from JPNIC, replaces mdnkit. + +1471. [bug] libbind: updated to BIND 8.4.0. + +1470. [bug] Incorrect length passed to snprintf. [RT #5966] + +1469. [func] Log end of outgoing zone transfer at same level + as the start of transfer is logged. [RT #4441] + +1468. [func] Internal zones are no longer counted for + 'rndc status'. [RT #4706] + +1467. [func] $GENERATES now supports optional class and ttl. + +1466. [bug] lwresd configuration errors resulted in memory + and lock leaks. [RT #5228] + +1465. [bug] isc_base64_decodestring() and isc_base64_tobuffer() + failed to check that trailing bits were zero allowing + some invalid base64 strings to be accepted. [RT #5397] + +1464. [bug] Preserve "out of zone" data for outgoing zone + transfers. [RT #5192] + +1463. [bug] dns_rdata_from{wire,struct}() failed to catch bad + NXT bit maps. [RT #5577] + +1462. [bug] parse_sizeval() failed to check the token type. + [RT #5586] + +1461. [bug] Remove deadlock from rbtdb code. [RT #5599] + +1460. [bug] inet_pton() failed to reject certain malformed + IPv6 literals. + +1459. [placeholder] + +1458. [cleanup] sprintf() -> snprintf(). + +1457. [port] Provide strlcat() and strlcpy() for platforms without + them. + +1456. [contrib] gen-data-queryperf.py from Stephane Bortzmeyer. + +1455. [bug] missing from server grammar in + doc/misc/options. [RT #5616] + +1454. [port] Use getifaddrs() if available for interface scanning. + --disable-getifaddrs to override. Glibc currently + has a getifaddrs() that does not support IPv6. + Use --enable-getifaddrs=glibc to force the use of + this version under linux machines. + +1453. [doc] ARM: $GENERATE example wasn't accurate. [RT #5298] + +1452. [placeholder] + +1451. [bug] rndc-confgen didn't exit with a error code for all + failures. [RT #5209] + +1450. [bug] Fetching expired glue failed under certain + circumstances. [RT #5124] + +1449. [bug] query_addbestns() didn't handle running out of memory + gracefully. + +1448. [bug] Handle empty wildcards labels. + +1447. [bug] We were casting (unsigned int) to and from (void *). + rdataset->private4 is now rdataset->privateuint4 + to reflect a type change. + +1446. [func] Implemented undocumented alternate transfer sources + from BIND 8. See use-alt-transfer-source, + alt-transfer-source and alt-transfer-source-v6. + + SECURITY: use-alt-transfer-source is ENABLED unless + you are using views. This may cause a security risk + resulting in accidental disclosure of wrong zone + content if the master supplying different source + content based on IP address. If you are not certain + ISC recommends setting use-alt-transfer-source no; + +1445. [bug] DNS_ADBFIND_STARTATROOT broke stub zones. This has + been replaced with DNS_ADBFIND_STARTATZONE which + causes the search to start using the closest zone. + +1444. [func] dns_view_findzonecut2() allows you to specify if the + cache should be searched for zone cuts. + +1443. [func] Masters lists can now be specified and referenced + in zone masters clauses and other masters lists. + +1442. [func] New functions for manipulating port lists: + dns_portlist_create(), dns_portlist_add(), + dns_portlist_remove(), dns_portlist_match(), + dns_portlist_attach() and dns_portlist_detach(). + +1441. [func] It is now possible to tell dig to bind to a specific + source port. + +1440. [func] It is now possible to tell named to avoid using + certain source ports (avoid-v4-udp-ports, + avoid-v6-udp-ports). + +1439. [bug] Named could return NOERROR with certain NOTIFY + failures. Return NOTAUTH if the NOTIFY zone is + not being served. + +1438. [func] Log TSIG (if any) when logging NOTIFY requests. + +1437. [bug] Leave space for stdio to work in. [RT #5033] + +1436. [func] dns_zonemgr_resumexfrs() can be used to restart + stalled transfers. + +1435. [bug] zmgr_resume_xfrs() was being called read locked + rather than write locked. zmgr_resume_xfrs() + was not being called if the zone was being + shutdown. + +1434. [bug] "rndc reconfig" failed to initiate the initial + zone transfer of new slave zones. + +1433. [bug] named could trigger a REQUIRE failure if it could + not get a file descriptor when attempting to write + a master file. [RT #4347] + +1432. [func] The advertised EDNS UDP buffer size can now be set + via named.conf (edns-udp-size). + +1431. [bug] isc_print_snprintf() "%s" with precision could walk off + end of argument. [RT #5191] + +1430. [port] linux: IPv6 interface scanning support. + +1429. [bug] Prevent the cache getting locked to old servers. + +1428. [placeholder] + +1427. [bug] Race condition in adb with threaded build. + +1426. [placeholder] + +1425. [port] linux/libbind: define __USE_MISC when testing *_r() + function prototypes in netdb.h. [RT #4921] + +1424. [bug] EDNS version not being correctly printed. + +1423. [contrib] queryperf: added A6 and SRV. + +1422. [func] Log name/type/class when denying a query. [RT #4663] + +1421. [func] Differentiate updates that don't succeed due to + prerequisites (unsuccessful) vs other reasons + (failed). + +1420. [port] solaris: work around gcc optimizer bug. + +1419. [port] openbsd: use /dev/arandom. [RT #4950] + +1418. [bug] 'rndc reconfig' did not cause new slaves to load. + +1417. [func] ID.SERVER/CHAOS is now a built in zone. + See "server-id" for how to configure. + +1416. [bug] Empty node should return NOERROR NODATA, not NXDOMAIN. + [RT #4715] + +1415. [func] DS TTL now derived from NS ttl. NXT TTL now derived + from SOA MINIMUM. + +1414. [func] Support for KSK flag. + +1413. [func] Explicitly request the (re-)generation of DS records + from keysets (dnssec-signzone -g). + +1412. [func] You can now specify servers to be tried if a nameserver + has IPv6 address and you only support IPv4 or the + reverse. See dual-stack-servers. + +1411. [bug] empty nodes should stop wildcard matches. [RT #4802] + +1410. [func] Handle records that live in the parent zone, e.g. DS. + +1409. [bug] DS should have attribute DNS_RDATATYPEATTR_DNSSEC. + +1408. [bug] "make distclean" was not complete. [RT #4700] + +1407. [bug] lfsr incorrectly implements the shift register. + [RT #4617] + +1406. [bug] dispatch initializes one of the LFSR's with a incorrect + polynomial. [RT #4617] + +1405. [func] Use arc4random() if available. + +1404. [bug] libbind: ns_name_ntol() could overwrite a zero length + buffer. + +1403. [func] dnssec-signzone, dnssec-keygen, dnssec-makekeyset + dnssec-signkey now report their version in the + usage message. + +1402. [cleanup] A6 has been moved to experimental and is no longer + fully supported. + +1401. [bug] adb wasn't clearing state when the timer expired. + +1400. [bug] Block the addition of wildcard NS records by IXFR + or UPDATE. [RT #3502] + +1399. [bug] Use serial number arithmetic when testing SIG + timestamps. [RT #4268] + +1398. [doc] ARM: notify-also should have been also-notify. + [RT #4345] + +1397. [maint] J.ROOT-SERVERS.NET is now 192.58.128.30. + +1396. [func] dnssec-signzone: adjust the default signing time by + 1 hour to allow for clock skew. + +1395. [port] OpenSSL 0.9.7 defines CRYPTO_LOCK_ENGINE but doesn't + have a working implementation. [RT #4079] + +1394. [func] It is now possible to check if a particular element is + in a acl. Remove duplicate entries from the localnets + acl. + +1393. [port] Bind to individual IPv6 interfaces if IPV6_IPV6ONLY + is not available in the kernel to prevent accidently + listening on IPv4 interfaces. + +1392. [bug] named-checkzone: update usage. + +1391. [func] Add support for IPv6 scoped addresses in named. + +1390. [func] host now supports ixfr. + +1389. [bug] named could fail to rotate long log files. [RT #3666] + +1388. [port] irix: check for sys/sysctl.h and NET_RT_IFLIST before + defining HAVE_IFLIST_SYSCTL. [RT #3770] + +1387. [bug] named could crash due to an access to invalid memory + space (which caused an assertion failure) in + incremental cleaning. [RT #3588] + +1386. [bug] named-checkzone -z stopped on errors in a zone. + [RT #3653] + +1385. [bug] Setting serial-query-rate to 10 would trigger a + REQUIRE failure. + +1384. [bug] host was incompatible with BIND 8 in its exit code and + in the output with the -l option. [RT #3536] + +1383. [func] Track the serial number in a IXFR response and log if + a mismatch occurs. This is a more specific error than + "not exact". [RT #3445] + +1382. [bug] make install failed with --enable-libbind. [RT #3656] + +1381. [bug] named failed to correctly process answers that + contained DNAME records where the resulting CNAME + resulted in a negative answer. + +1380. [func] 'rndc recursing' dump recursing queries to + 'recursing-file = "named.recursing";'. + +1379. [func] 'rndc status' now reports tcp and recursion quota + states. + +1378. [func] Improved positive feedback for 'rndc {reload|refresh}. + +1377. [func] dns_zone_load{new}() now reports if the zone was + loaded, queued for loading to up to date. + +1376. [func] New function dns_zone_logc() to log to specified + category. + +1375. [func] 'rndc dumpdb' now dumps the adb cache along with the + data cache. + +1374. [func] dns_adb_dump() now logs the lame zones associated + with each server. + +1373. [bug] Recovery from expired glue failed under certain + circumstances. + +1372. [bug] named crashes with an assertion failure on exit when + sharing the same port for listening and querying, and + changing listening addresses several times. [RT# 3509] + +1371. [bug] notify-source-v6, transfer-source-v6 and + query-source-v6 with explicit addresses and using the + same ports as named was listening on could interfere + with named's ability to answer queries sent to those + addresses. + +1370. [bug] dig '+[no]recurse' was incorrectly documented. + +1369. [bug] Adding an NS record as the lexicographically last + record in a secure zone didn't work. + +1368. [func] remove support for bitstring labels. + +1367. [func] Use response times to select forwarders. + +1366. [contrib] queryperf usage was incomplete. Add '-h' for help. + +1365. [func] "localhost" and "localnets" acls now include IPv6 + addresses / prefixes. + +1364. [func] Log file name when unable to open memory statistics + and dump database files. [RT# 3437] + +1363. [func] Listen-on-v6 now supports specific addresses. + +1362. [bug] remove IFF_RUNNING test when scanning interfaces. + +1361. [func] log the reason for rejecting a server when resolving + queries. + +1360. [bug] --enable-libbind would fail when not built in the + source tree for certain OS's. + +1359. [security] Support patches OpenSSL libraries. + http://www.cert.org/advisories/CA-2002-23.html + +1358. [bug] It was possible to trigger a INSIST when debugging + large dynamic updates. [RT #3390] + +1357. [bug] nsupdate was extremely wasteful of memory. + +1356. [tuning] Reduce the number of events / quantum for zone tasks. + +1355. [bug] Fix DNSSEC wildcard proof for CNAME/DNAME. + +1354. [doc] lwres man pages had illegal nroff. + +1353. [contrib] sdb/ldap to version 0.9. + +1352. [bug] dig, host, nslookup when falling back to TCP use the + current search entry (if any). [RT #3374] + +1351. [bug] lwres_getipnodebyname() returned the wrong name + when given a IPv4 literal, af=AF_INET6 and AI_MAPPED + was set. + +1350. [bug] dns_name_fromtext() failed to handle too many labels + gracefully. + +1349. [security] Minimum OpenSSL version now 0.9.6e (was 0.9.5a). + http://www.cert.org/advisories/CA-2002-23.html + +1348. [port] win32: Rewrote code to use I/O Completion Ports + in socket.c and eliminating a host of socket + errors. Performance is enhanced. + +1347. [placeholder] + +1346. [placeholder] + +1345. [port] Use a explicit -Wformat with gcc. Not all versions + include it in -Wall. + +1344. [func] Log if the serial number on the master has gone + backwards. + If you have multiple machines specified in the masters + clause you may want to set 'multi-master yes;' to + suppress this warning. + +1343. [func] Log successful notifies received (info). Adjust log + level for failed notifies to notice. + +1342. [func] Log remote address with TCP dispatch failures. + +1341. [func] Allow a rate limiter to be stalled. + +1340. [bug] Delay and spread out the startup refresh load. + +1339. [func] dig, host and nslookup now use IP6.ARPA for nibble + lookups. Bit string lookups are no longer attempted. + +1338. [placeholder] + +1337. [placeholder] + +1336. [func] Nibble lookups under IP6.ARPA are now supported by + dns_byaddr_create(). dns_byaddr_createptrname() is + deprecated, use dns_byaddr_createptrname2() instead. + +1335. [bug] When performing a nonexistence proof, the validator + should discard parent NXTs from higher in the DNS. + +1334. [bug] When signing/verifying rdatasets, duplicate rdatas + need to be suppressed. + +1333. [contrib] queryperf now reports a summary of returned + rcodes (-c), rcodes are printed in mnemonic form (-v). + +1332. [func] Report the current serial with periodic commits when + rolling forward the journal. + +1331. [func] Generate DNSSEC wildcard proofs. + +1330. [bug] When processing events (non-threaded) only allow + the task one chance to use to use its quantum. + +1329. [func] named-checkzone will now check if nameservers that + appear to be IP addresses. Available modes "fail", + "warn" (default) and "ignore" the results of the + check. + +1328. [bug] The validator could incorrectly verify an invalid + negative proof. + +1327. [bug] The validator would incorrectly mark data as insecure + when seeing a bogus signature before a correct + signature. + +1326. [bug] DNAME/CNAME signatures were not being cached when + validation was not being performed. [RT #3284] + +1325. [bug] If the tcpquota was exhausted it was possible to + to trigger a INSIST() failure. + +1324. [port] darwin: ifconfig.sh now supports darwin. + +1323. [port] linux: Slackware 4.0 needs . [RT #3205] + +1322. [bug] dnssec-signzone usage message was misleading. + +1321. [bug] If the last RRset in a zone is glue, dnssec-signzone + would incorrectly duplicate its output and sign it. + +1320. [doc] query-source-v6 was missing from options section. + [RT #3218] + +1319. [func] libbind: log attempts to exploit #1318. + +1318. [bug] libbind: Remote buffer overrun. + +1317. [port] libbind: TrueUNIX 5.1 does not like __align as a + element name. + +1316. [bug] libbind: gethostans() could get out of sync parsing + the response if there was a very long CNAME chain. + +1315. [bug] Options should apply to the internal _bind view. + +1314. [port] Handle ECONNRESET from sendmsg() [unix]. + +1313. [func] Query log now says if the query was signed (S) or + if EDNS was used (E). + +1312. [func] Log TSIG key used w/ outgoing zone transfers. + +1311. [bug] lwres_getrrsetbyname leaked memory. [RT #3159] + +1310. [bug] 'rndc stop' failed to cause zones to be flushed + sometimes. [RT #3157] + +1309. [func] Log that a zone transfer was covered by a TSIG. + +1308. [func] DS (delegation signer) support. + +1307. [bug] nsupdate: allow white space base64 key data. + +1306. [bug] Badly encoded LOC record when the size, horizontal + precision or vertical precision was 0.1m. + +1305. [bug] Document that internal zones are included in the + rndc status results. + +1304. [func] New function: dns_zone_name(). + +1303. [func] Option 'flush-zones-on-shutdown ;'. + +1302. [func] Extended rndc dumpdb to support dumping of zones and + view selection: 'dumpdb [-all|-zones|-cache] [view]'. + +1301. [func] New category 'update-security'. + +1300. [port] Compaq Trucluster support. + +1299. [bug] Set AI_ADDRCONFIG when looking up addresses + via getaddrinfo() (affects dig, host, nslookup, rndc + and nsupdate). + +1298. [bug] The CINCLUDES macro in lib/dns/sec/dst/Makefile + could be left with a trailing "\" after configure + has been run. + +1297. [port] linux: make handling EINVAL from socket() no longer + conditional on #ifdef LINUX. + +1296. [bug] isc_log_closefilelogs() needed to lock the log + context. + +1295. [bug] isc_log_setdebuglevel() needed to lock the log + context. + +1294. [func] libbind: no longer attempts bit string labels for + IPv6 reverse resolution. Try IP6.ARPA then IP6.INT + for nibble style resolution. + +1293. [func] Entropy can now be retrieved from EGDs. [RT #2438] + +1292. [func] Enable IPv6 support when using ioctl style interface + scanning and OS supports SIOCGLIFADDR using struct + if_laddrreq. + +1291. [func] Enable IPv6 support when using sysctl style interface + scanning. + +1290. [func] "dig axfr" now reports the number of messages + as well as the number of records. + +1289. [port] See if -ldl is required for OpenSSL? [RT #2672] + +1288. [bug] Adjusted REQUIRE's in lib/dns/name.c to better + reflect written requirements. + +1287. [bug] REQUIRE that DNS_DBADD_MERGE only be set when adding + a rdataset to a zone db in the rbtdb implementation of + addrdataset. + +1286. [bug] dns_name_downcase() enforce requirement that + target != NULL or name->buffer != NULL. + +1285. [func] lwres: probe the system to see what address families + are currently in use. + +1284. [bug] The RTT estimate on unused servers was not aged. + [RT #2569] + +1283. [func] Use "dataready" accept filter if available. + +1282. [port] libbind: hpux 11.11 interface scanning. + +1281. [func] Log zone when unable to get private keys to update + zone. Log zone when NXT records are missing from + secure zone. + +1280. [bug] libbind: escape '(' and ')' when converting to + presentation form. + +1279. [port] Darwin uses (unsigned long) for size_t. [RT #2590] + +1278. [func] dig: now supports +[no]cl +[no]ttlid. + +1277. [func] You can now create your own customized printing + styles: dns_master_stylecreate() and + dns_master_styledestroy(). + +1276. [bug] libbind: const pointer conflicts in res_debug.c. + +1275. [port] libbind: hpux: treat all hpux systems as BIG_ENDIAN. + +1274. [bug] Memory leak in lwres_gnbarequest_parse(). + +1273. [port] libbind: solaris: 64 bit binary compatibility. + +1272. [contrib] Berkeley DB 4.0 sdb implementation from + Nuno Miguel Rodrigues . + +1271. [bug] "recursion available: {denied,approved}" was too + confusing. + +1270. [bug] Check that system inet_pton() and inet_ntop() support + AF_INET6. + +1269. [port] Openserver: ifconfig.sh support. + +1268. [port] Openserver: the value FD_SETSIZE depends on whether + is included or not. Be consistent. + +1267. [func] isc_file_openunique() now creates file using mode + 0666 rather than 0600. + +1266. [bug] ISC_LINK_INIT, ISC_LINK_UNLINK, ISC_LIST_DEQUEUE, + __ISC_LINK_UNLINKUNSAFE and __ISC_LIST_DEQUEUEUNSAFE + are not C++ compatible, use *_TYPE versions instead. + +1265. [bug] libbind: LINK_INIT and UNLINK were not compatible with + C++, use LINK_INIT_TYPE and UNLINK_TYPE instead. + +1264. [placeholder] + +1263. [bug] Reference after free error if dns_dispatchmgr_create() + failed. + +1262. [bug] ns_server_destroy() failed to set *serverp to NULL. + +1261. [func] libbind: ns_sign2() and ns_sign_tcp() now provide + support for compressed TSIG owner names. + +1260. [func] libbind: res_update can now update IPv6 servers, + new function res_findzonecut2(). + +1259. [bug] libbind: get_salen() IPv6 support was broken for OSs + w/o sa_len. + +1258. [bug] libbind: res_nametotype() and res_nametoclass() were + broken. + +1257. [bug] Failure to write pid-file should not be fatal on + reload. [RT #2861] + +1256. [contrib] 'queryperf' now has EDNS (-e) + DNSSEC DO (-D) support. + +1255. [bug] When verifying that an NXT proves nonexistence, check + the rcode of the message and only do the matching NXT + check. That is, for NXDOMAIN responses, check that + the name is in the range between the NXT owner and + next name, and for NOERROR NODATA responses, check + that the type is not present in the NXT bitmap. + +1254. [func] preferred-glue option from BIND 8.3. + +1253. [bug] The dnssec system test failed to remove the correct + files. + +1252. [bug] Dig, host and nslookup were not checking the address + the answer was coming from against the address it was + sent to. [RT# 2692] + +1251. [port] win32: a make file contained absolute version specific + references. + +1250. [func] Nsupdate will report the address the update was + sent to. + +1249. [bug] Missing masters clause was not handled gracefully. + [RT #2703] + +1248. [bug] DESTDIR was not being propagated between makes. + +1247. [bug] Don't reset the interface index for link/site local + addresses. [RT #2576] + +1246. [func] New functions isc_sockaddr_issitelocal(), + isc_sockaddr_islinklocal(), isc_netaddr_issitelocal() + and isc_netaddr_islinklocal(). + +1245. [bug] Treat ENOBUFS, ENOMEM and ENFILE as soft errors for + accept(). + +1244. [bug] Receiving a TCP message from a blackhole address would + prevent further messages being received over that + interface. + +1243. [bug] It was possible to trigger a REQUIRE() in + dns_message_findtype(). [RT #2659] + +1242. [bug] named-checkzone failed if a journal existed. [RT #2657] + +1241. [bug] Drop received UDP messages with a zero source port + as these are invariably forged. [RT #2621] + +1240. [bug] It was possible to leak zone references by + specifying an incorrect zone to rndc. + +1239. [bug] Under certain circumstances named could continue to + use a name after it had been freed triggering + INSIST() failures. [RT #2614] + +1238. [bug] It is possible to lockup the server when shutting down + if notifies were being processed. [RT #2591] + +1237. [bug] nslookup: "set q=type" failed. + +1236. [bug] dns_rdata{class,type}_fromtext() didn't handle non + NULL terminated text regions. [RT #2588] + +1235. [func] Report 'out of memory' errors from openssl. + +1234. [bug] contrib/sdb: 'zonetodb' failed to call + dns_result_register(). DNS_R_SEENINCLUDE should not + be fatal. + +1233. [bug] The flags field of a KEY record can be expressed in + hex as well as decimal. + +1232. [bug] unix/errno2result() didn't handle EADDRNOTAVAIL. + +1231. [port] HPUX 11.11 recvmsg() can return spurious EADDRNOTAVAIL. + +1230. [bug] isccc_cc_isreply() and isccc_cc_isack() were broken. + +1229. [bug] named would crash if it received a TSIG signed + query as part of an AXFR response. [RT #2570] + +1228. [bug] 'make install' did not depend on 'make all'. [RT #2559] + +1227. [bug] dns_lex_getmastertoken() now returns ISC_R_BADNUMBER + if a number was expected and some other token was + found. [RT#2532] + +1226. [func] Use EDNS for zone refresh queries. [RT #2551] + +1225. [func] dns_message_setopt() no longer requires that + dns_message_renderbegin() to have been called. + +1224. [bug] 'rrset-order' and 'sortlist' should be additive + not exclusive. + +1223. [func] 'rrset-order' partially works 'cyclic' and 'random' + are supported. + +1222. [bug] Specifying 'port *' did not always result in a system + selected (non-reserved) port being used. [RT #2537] + +1221. [bug] Zone types 'master', 'slave' and 'stub' were not being + compared case insensitively. [RT #2542] + +1220. [func] Support for APL rdata type. + +1219. [func] Named now reports the TSIG extended error code when + signature verification fails. [RT #1651] + +1218. [bug] Named incorrectly returned SERVFAIL rather than + NOTAUTH when there was a TSIG BADTIME error. [RT #2519] + +1217. [func] Report locations of previous key definition when a + duplicate is detected. + +1216. [bug] Multiple server clauses for the same server were not + reported. [RT #2514] + +1215. [port] solaris: add support to ifconfig.sh for x86 2.5.1 + +1214. [bug] Win32: isc_file_renameunique() could leave zero length + files behind. + +1213. [func] Report view associated with client if it is not a + standard view (_default or _bind). + +1212. [port] libbind: 64k answer buffers were causing stack space + to be exceeded for certain OS. Use heap space instead. + +1211. [bug] dns_name_fromtext() incorrectly handled certain + valid octal bitlabels. [RT #2483] + +1210. [bug] libbind: getnameinfo() failed to lookup IPv4 mapped / + compatible addresses. [RT #2461] + +1209. [bug] Dig, host, nslookup were not checking the message ids + on the responses. [RT #2454] + +1208. [bug] dns_master_load*() failed to log a error message if + an error was detected when parsing the ownername of + a record. [RT #2448] + +1207. [bug] libbind: getaddrinfo() could call freeaddrinfo() with + an invalid pointer. + +1206. [bug] SERVFAIL and NOTIMP responses to an EDNS query should + trigger a non-EDNS retry. + +1205. [bug] OPT, TSIG and TKEY cannot be used to set the "class" + of the message. [RT #2449] + +1204. [bug] libbind: res_nupdate() failed to update the name + server addresses before sending the update. + +1203. [func] Report locations of previous acl and zone definitions + when a duplicate is detected. + +1202. [func] New functions: cfg_obj_line() and cfg_obj_file(). + +1201. [bug] Require that if 'callbacks' is passed to + dns_rdata_fromtext(), callbacks->error and + callbacks->warn are initialized. + +1200. [bug] Log 'errno' that we are unable to convert to + isc_result_t. [RT #2404] + +1199. [doc] ARM reference to RFC 2157 should have been RFC 1918. + [RT #2436] + +1198. [bug] OPT printing style was not consistent with the way the + header fields are printed. The DO bit was not reported + if set. Report if any of the MBZ bits are set. + +1197. [bug] Attempts to define the same acl multiple times were not + detected. + +1196. [contrib] update mdnkit to 2.2.3. + +1195. [bug] Attempts to redefine builtin acls should be caught. + [RT #2403] + +1194. [bug] Not all duplicate zone definitions were being detected + at the named.conf checking stage. [RT #2431] + +1193. [bug] dig +besteffort parsing didn't handle packet + truncation. dns_message_parse() has new flag + DNS_MESSAGE_IGNORETRUNCATION. + +1192. [bug] The seconds fields in LOC records were restricted + to three decimal places. More decimal places should + be allowed but warned about. + +1191. [bug] A dynamic update removing the last non-apex name in + a secure zone would fail. [RT #2399] + +1190. [func] Add the "rndc freeze" and "rndc unfreeze" commands. + [RT #2394] + +1189. [bug] On some systems, malloc(0) returns NULL, which + could cause the caller to report an out of memory + error. [RT #2398] + +1188. [bug] Dynamic updates of a signed zone would fail if + some of the zone private keys were unavailable. + +1187. [bug] named was incorrectly returning DNSSEC records + in negative responses when the DO bit was not set. + +1186. [bug] isc_hex_tobuffer(,,length = 0) failed to unget the + EOL token when reading to end of line. + +1185. [bug] libbind: don't assume statp->_u._ext.ext is valid + unless RES_INIT is set when calling res_*init(). + +1184. [bug] libbind: call res_ndestroy() if RES_INIT is set + when res_*init() is called. + +1183. [bug] Handle ENOSR error when writing to the internal + control pipe. [RT #2395] + +1182. [bug] The server could throw an assertion failure when + constructing a negative response packet. + +1181. [func] Add the "key-directory" configuration statement, + which allows the server to look for online signing + keys in alternate directories. + +1180. [func] dnssec-keygen should always generate keys with + protocol 3 (DNSSEC), since it's less confusing + that way. + +1179. [func] Add SIG(0) support to nsupdate. + +1178. [bug] Follow and cache (if appropriate) A6 and other + data chains to completion in the additional section. + +1177. [func] Report view when loading zones if it is not a + standard view (_default or _bind). [RT #2270] + +1176. [doc] Document that allow-v6-synthesis is only performed + for clients that are supplied recursive service. + [RT #2260] + +1175. [bug] named-checkzone and named-checkconf failed to call + dns_result_register() at startup which could + result in runtime exceptions when printing + "out of memory" errors. [RT #2335] + +1174. [bug] Win32: add WSAECONNRESET to the expected errors + from connect(). [RT #2308] + +1173. [bug] Potential memory leaks in isc_log_create() and + isc_log_settag(). [RT #2336] + +1172. [doc] Add CERT, GPOS, KX, NAPTR, NSAP, PX and TXT to + table of RR types in ARM. + +1171. [func] Added function isc_region_compare(), updated files in + lib/dns to use this function instead of local one. + +1170. [bug] Don't attempt to print the token when a I/O error + occurs when parsing named.conf. [RT #2275] + +1169. [func] Identify recursive queries in the query log. + +1168. [bug] Empty also-notify clauses were not handled. [RT #2309] + +1167. [contrib] nslint-2.1a3 (from author). + +1166. [bug] "Not Implemented" should be reported as NOTIMP, + not NOTIMPL. [RT #2281] + +1165. [bug] We were rejecting notify-source{-v6} in zone clauses. + +1164. [bug] Empty masters clauses in slave / stub zones were not + handled gracefully. [RT #2262] + +1163. [func] isc_time_formattimestamp() now includes the year. + +1162. [bug] The allow-notify option was not accepted in slave + zone statements. + +1161. [bug] named-checkzone looped on unbalanced brackets. + [RT #2248] + +1160. [bug] Generating Diffie-Hellman keys longer than 1024 + bits could fail. [RT #2241] + +1159. [bug] MD and MF are not permitted to be loaded by RFC1123. + +1158. [func] Report the client's address when logging notify + messages. + +1157. [func] match-clients and match-destinations now accept + keys. [RT #2045] + +1156. [port] The configure test for strsep() incorrectly + succeeded on certain patched versions of + AIX 4.3.3. [RT #2190] + +1155. [func] Recover from master files being removed from under + us. + +1154. [bug] Don't attempt to obtain the netmask of a interface + if there is no address configured. [RT #2176] + +1153. [func] 'rndc {stop|halt} -p' now reports the process id + of the instance of named being shutdown. + +1152. [bug] libbind: read buffer overflows. + +1151. [bug] nslookup failed to check that the arguments to + the port, timeout, and retry options were + valid integers and in range. [RT #2099] + +1150. [bug] named incorrectly accepted TTL values + containing plus or minus signs, such as + 1d+1h-1s. + +1149. [func] New function isc_parse_uint32(). + +1148. [func] 'rndc-confgen -a' now provides positive feedback. + +1147. [func] Set IPV6_V6ONLY on IPv6 sockets if supported by + the OS. listen-on-v6 { any; }; should no longer + result in IPv4 queries be accepted. Similarly + control { inet :: ... }; should no longer result + in IPv4 connections being accepted. This can be + overridden at compile time by defining + ISC_ALLOW_MAPPED=1. + +1146. [func] Allow IPV6_IPV6ONLY to be set/cleared on a socket if + supported by the OS by a new function + isc_socket_ipv6only(). + +1145. [func] "host" no longer reports a NOERROR/NODATA response + by printing nothing. [RT #2065] + +1144. [bug] rndc-confgen would crash if both the -a and -t + options were specified. [RT #2159] + +1143. [bug] When a trusted-keys statement was present and named + was built without crypto support, it would leak memory. + +1142. [bug] dnssec-signzone would fail to delete temporary files + in some failure cases. [RT #2144] + +1141. [bug] When named rejected a control message, it would + leak a file descriptor and memory. It would also + fail to respond, causing rndc to hang. + [RT #2139, #2164] + +1140. [bug] rndc-confgen did not accept IPv6 addresses as arguments + to the -s option. [RT #2138] + +1139. [func] It is now possible to flush a given name from the + cache(s) via 'rndc flushname name [view]'. [RT #2051] + +1138. [func] It is now possible to flush a given name from the + cache by calling the new function + dns_cache_flushname(). + +1137. [func] It is now possible to flush a given name from the + ADB by calling the new function dns_adb_flushname(). + +1136. [bug] CNAME records synthesized from DNAMEs did not + have a TTL of zero as required by RFC2672. + [RT #2129] + +1135. [func] You can now override the default syslog() facility for + named/lwresd at compile time. [RT #1982] + +1134. [bug] Multi-threaded servers could deadlock in ferror() + when reloading zone files. [RT #1951, #1998] + +1133. [bug] IN6_IS_ADDR_LOOPBACK was not portably defined on + platforms without IN6_IS_ADDR_LOOPBACK. [RT #2106] + +1132. [func] Improve UPDATE prerequisite failure diagnostic messages. + +1131. [bug] The match-destinations view option did not work with + IPv6 destinations. [RT #2073, #2074] + +1130. [bug] Log messages reporting an out-of-range serial number + did not include the out-of-range number but the + following token. [RT #2076] + +1129. [bug] Multi-threaded servers could crash under heavy + resolution load due to a race condition. [RT #2018] + +1128. [func] sdb drivers can now provide RR data in either text + or wire format, the latter using the new functions + dns_sdb_putrdata() and dns_sdb_putnamedrdata(). + +1127. [func] rndc: If the server to contact has multiple addresses, + try all of them. + +1126. [bug] The server could access a freed event if shut + down while a client start event was pending + delivery. [RT #2061] + +1125. [bug] rndc: -k option was missing from usage message. + [RT #2057] + +1124. [doc] dig: +[no]dnssec, +[no]besteffort and +[no]fail + are now documented. [RT #2052] + +1123. [bug] dig +[no]fail did not match description. [RT #2052] + +1122. [tuning] Resolution timeout reduced from 90 to 30 seconds. + [RT #2046] + +1121. [bug] The server could attempt to access a NULL zone + table if shut down while resolving. + [RT #1587, #2054] + +1120. [bug] Errors in options were not fatal. [RT #2002] + +1119. [func] Added support in Win32 for NTFS file/directory ACL's + for access control. + +1118. [bug] On multi-threaded servers, a race condition + could cause an assertion failure in resolver.c + during resolver shutdown. [RT #2029] + +1117. [port] The configure check for in6addr_loopback incorrectly + succeeded on AIX 4.3 when compiling with -O2 + because the test code was optimized away. + [RT #2016] + +1116. [bug] Setting transfers in a server clause, transfers-in, + or transfers-per-ns to a value greater than + 2147483647 disabled transfers. [RT #2002] + +1115. [func] Set maximum values for cleaning-interval, + heartbeat-interval, interface-interval, + max-transfer-idle-in, max-transfer-idle-out, + max-transfer-time-in, max-transfer-time-out, + statistics-interval of 28 days and + sig-validity-interval of 3660 days. [RT #2002] + +1114. [port] Ignore more accept() errors. [RT #2021] + +1113. [bug] The allow-update-forwarding option was ignored + when specified in a view. [RT #2014] + +1112. [placeholder] + +1111. [bug] Multi-threaded servers could deadlock processing + recursive queries due to a locking hierarchy + violation in adb.c. [RT #2017] + +1110. [bug] dig should only accept valid abbreviations of +options. + [RT #2003] + +1109. [bug] nsupdate accepted illegal ttl values. + +1108. [bug] On Win32, rndc was hanging when named was not running + due to failure to select for exceptional conditions + in select(). [RT #1870] + +1107. [bug] nsupdate could catch an assertion failure if an + invalid domain name was given as the argument to + the "zone" command. + +1106. [bug] After seeing an out of range TTL, nsupdate would + treat all TTLs as out of range. [RT #2001] + +1105. [port] OpenUNIX 8 enable threads by default. [RT #1970] + +1104. [bug] Invalid arguments to the transfer-format option + could cause an assertion failure. [RT #1995] + +1103. [port] OpenUNIX 8 support (ifconfig.sh). [RT #1970] + +1102. [doc] Note that query logging is enabled by directing the + queries category to a channel. + +1101. [bug] Array bounds read error in lwres_gai_strerror. + +1100. [bug] libbind: DNSSEC key ids were computed incorrectly. + +1099. [cleanup] libbind: defining REPORT_ERRORS in lib/bind/dst caused + compile time errors. + +1098. [bug] libbind: HMAC-MD5 key files are now mode 0600. + +1097. [func] libbind: RES_PRF_TRUNC for dig. + +1096. [func] libbind: "DNSSEC OK" (DO) support. + +1095. [func] libbind: resolver option: no-tld-query. disables + trying unqualified as a tld. no_tld_query is also + supported for FreeBSD compatibility. + +1094. [func] libbind: add support gcc's format string checking. + +1093. [doc] libbind: miscellaneous nroff fixes. + +1092. [bug] libbind: get*by*() failed to check if res_init() had + been called. + +1091. [bug] libbind: misplaced va_end(). + +1090. [bug] libbind: dns_ho.c:add_hostent() was not returning + the amount of memory consumed resulting in garbage + address being returned. Alignment calculations were + wasting space. We weren't suppressing duplicate + addresses. + +1089. [func] libbind: inet_{cidr,net}_{pton,ntop}() now have IPv6 + support. + +1088. [port] libbind: MPE/iX C.70 (incomplete) + +1087. [bug] libbind: struct __res_state too large on 64 bit arch. + +1086. [port] libbind: sunos: old sprintf. + +1085. [port] libbind: solaris: sys_nerr and sys_errlist do not + exist when compiling in 64 bit mode. + +1084. [cleanup] libbind: gai_strerror() rewritten. + +1083. [bug] The default control channel listened on the + wildcard address, not the loopback as documented. + [RT #1975] + +1082. [bug] The -g option to named incorrectly caused logging + to be sent to syslog in addition to stderr. + [RT #1974] + +1081. [bug] Multicast queries were incorrectly identified + based on the source address, not the destination + address. + +1080. [bug] BIND 8 compatibility: accept bare IP prefixes + as the second element of a two-element top level + sort list statement. [RT #1964] + +1079. [bug] BIND 8 compatibility: accept bare elements at top + level of sort list treating them as if they were + a single element list. [RT #1963] + +1078. [bug] We failed to correct bad tv_usec values in one case. + [RT #1966] + +1077. [func] Do not accept further recursive clients when + the total number of recursive lookups being + processed exceeds max-recursive-clients, even + if some of the lookups are internally generated. + [RT #1915, #1938] + +1076. [bug] A badly defined global key could trigger an assertion + on load/reload if views were used. [RT #1947] + +1075. [bug] Out-of-range network prefix lengths were not + reported. [RT #1954] + +1074. [bug] Running out of memory in dump_rdataset() could + cause an assertion failure. [RT #1946] + +1073. [bug] The ADB cache cleaning should also be space driven. + [RT #1915, #1938] + +1072. [bug] The TCP client quota could be exceeded when + recursion occurred. [RT #1937] + +1071. [bug] Sockets listening for TCP DNS connections + specified an excessive listen backlog. [RT #1937] + +1070. [bug] Copy DNSSEC OK (DO) to response as specified by + draft-ietf-dnsext-dnssec-okbit-03.txt. + +1069. [placeholder] + +1068. [bug] errno could be overwritten by catgets(). [RT #1921] + +1067. [func] Allow quotas to be soft, isc_quota_soft(). + +1066. [bug] Provide a thread safe wrapper for strerror(). + [RT #1689] + +1065. [func] Runtime support to select new / old style interface + scanning using ioctls. + +1064. [bug] Do not shut down active network interfaces if we + are unable to scan the interface list. [RT #1921] + +1063. [bug] libbind: "make install" was failing on IRIX. + [RT #1919] + +1062. [bug] If the control channel listener socket was shut + down before server exit, the listener object could + be freed twice. [RT #1916] + +1061. [bug] If periodic cache cleaning happened to start + while cleaning due to reaching the configured + maximum cache size was in progress, the server + could catch an assertion failure. [RT #1912] + +1060. [func] Move refresh, stub and notify UDP retry processing + into dns_request. + +1059. [func] dns_request now support will now retry UDP queries, + dns_request_createvia2() and dns_request_createraw2(). + +1058. [func] Limited lifetime ticker timers are now available, + isc_timertype_limited. + +1057. [bug] Reloading the server after adding a "file" clause + to a zone statement could cause the server to + crash due to a typo in change 1016. + +1056. [bug] Rndc could catch an assertion failure on SIGINT due + to an uninitialized variable. [RT #1908] + +1055. [func] Version and hostname queries can now be disabled + using "version none;" and "hostname none;", + respectively. + +1054. [bug] On Win32, cfg_categories and cfg_modules need to be + exported from the libisccfg DLL. + +1053. [bug] Dig did not increase its timeout when receiving + AXFRs unless the +time option was used. [RT #1904] + +1052. [bug] Journals were not being created in binary mode + resulting in "journal format not recognized" error + under Win32. [RT #1889] + +1051. [bug] Do not ignore a network interface completely just + because it has a noncontiguous netmask. Instead, + omit it from the localnets ACL and issue a warning. + [RT #1891] + +1050. [bug] Log messages reporting malformed IP addresses in + address lists such as that of the forwarders option + failed to include the correct error code, file + name, and line number. [RT #1890] + +1049. [func] "pid-file none;" will disable writing a pid file. + [RT #1848] + +1048. [bug] Servers built with -DISC_MEM_USE_INTERNAL_MALLOC=1 + didn't work. + +1047. [bug] named was incorrectly refusing all requests signed + with a TSIG key derived from an unsigned TKEY + negotiation with a NOERROR response. [RT #1886] + +1046. [bug] The help message for the --with-openssl configure + option was inaccurate. [RT #1880] + +1045. [bug] It was possible to skip saving glue for a nameserver + for a stub zone. + +1044. [bug] Specifying allow-transfer, notify-source, or + notify-source-v6 in a stub zone was not treated + as an error. + +1043. [bug] Specifying a transfer-source or transfer-source-v6 + option in the zone statement for a master zone was + not treated as an error. [RT #1876] + +1042. [bug] The "config" logging category did not work properly. + [RT #1873] + +1041. [bug] Dig/host/nslookup could catch an assertion failure + on SIGINT due to an uninitialized variable. [RT #1867] + +1040. [bug] Multiple listen-on-v6 options with different ports + were not accepted. [RT #1875] + +1039. [bug] Negative responses with CNAMEs in the answer section + were cached incorrectly. [RT #1862] + +1038. [bug] In servers configured with a tkey-domain option, + TKEY queries with an owner name other than the root + could cause an assertion failure. [RT #1866, #1869] + +1037. [bug] Negative responses whose authority section contain + SOA or NS records whose owner names are not equal + equal to or parents of the query name should be + rejected. [RT #1862] + +1036. [func] Silently drop requests received via multicast as + long as there is no final multicast DNS standard. + +1035. [bug] If we respond to multicast queries (which we + currently do not), respond from a unicast address + as specified in RFC 1123. [RT #137] + +1034. [bug] Ignore the RD bit on multicast queries as specified + in RFC 1123. [RT #137] + +1033. [bug] Always respond to requests with an unsupported opcode + with NOTIMP, even if we don't have a matching view + or cannot determine the class. + +1032. [func] hostname.bind/txt/chaos now returns the name of + the machine hosting the nameserver. This is useful + in diagnosing problems with anycast servers. + +1031. [bug] libbind.a: isc__gettimeofday() infinite recursion. + [RT #1858] + +1030. [bug] On systems with no resolv.conf file, nsupdate + exited with an error rather than defaulting + to using the loopback address. [RT #1836] + +1029. [bug] Some named.conf errors did not cause the loading + of the configuration file to return a failure + status even though they were logged. [RT #1847] + +1028. [bug] On Win32, dig/host/nslookup looked for resolv.conf + in the wrong directory. [RT #1833] + +1027. [bug] RRs having the reserved type 0 should be rejected. + [RT #1471] + +1026. [placeholder] + +1025. [bug] Don't use multicast addresses to resolve iterative + queries. [RT #101] + +1024. [port] Compilation failed on HP-UX 11.11 due to + incompatible use of the SIOCGLIFCONF macro + name. [RT #1831] + +1023. [func] Accept hints without TTLs. + +1022. [bug] Don't report empty root hints as "extra data". + [RT #1802] + +1021. [bug] On Win32, log message timestamps were one month + later than they should have been, and the server + would exhibit unspecified behavior in December. + +1020. [bug] IXFR log messages did not distinguish between + true IXFRs, AXFR-style IXFRs, and mere version + polls. [RT #1811] + +1019. [bug] The value of the lame-ttl option was limited to 18000 + seconds, not 1800 seconds as documented. [RT #1803] + +1018. [bug] The default log channel was not always initialized + correctly. [RT #1813] + +1017. [bug] When specifying TSIG keys to dig and nsupdate using + the -k option, they must be HMAC-MD5 keys. [RT #1810] + +1016. [bug] Slave zones with no backup file were re-transferred + on every server reload. + +1015. [bug] Log channels that had a "versions" option but no + "size" option failed to create numbered log + files. [RT #1783] + +1014. [bug] Some queries would cause statistics counters to + increment more than once or not at all. [RT #1321] + +1013. [bug] It was possible to cancel a query twice when marking + a server as bogus or by having a blackhole acl. + [RT #1776] + +1012. [bug] The -p option to named did not behave as documented. + +1011. [cleanup] Removed isc_dir_current(). + +1010. [bug] The server could attempt to execute a command channel + command after initiating server shutdown, causing + an assertion failure. [RT #1766] + +1009. [port] OpenUNIX 8 support. [RT #1728] + +1008. [port] libtool.m4, ltmain.sh from libtool-1.4.2. + +1007. [port] config.guess, config.sub from autoconf-2.52. + +1006. [bug] If a KEY RR was found missing during DNSSEC validation, + an assertion failure could subsequently be triggered + in the resolver. [RT #1763] + +1005. [bug] Don't copy nonzero RCODEs from request to response. + [RT #1765] + +1004. [port] Deal with recvfrom() returning EHOSTDOWN. [RT #1770] + +1003. [func] Add the +retry option to dig. + +1002. [bug] When reporting an unknown class name in named.conf, + including the file name and line number. [RT #1759] + +1001. [bug] win32 socket code doio_recv was not catching a + WSACONNRESET error when a client was timing out + the request and closing its socket. [RT #1745] + +1000. [bug] BIND 8 compatibility: accept "HESIOD" as an alias + for class "HS". [RT #1759] + + 999. [func] "rndc retransfer zone [class [view]]" added. + [RT #1752] + + 998. [func] named-checkzone now has arguments to specify the + chroot directory (-t) and working directory (-w). + [RT #1755] + + 997. [func] Add support for RSA-SHA1 keys (RFC3110). + + 996. [func] Issue warning if the configuration filename contains + the chroot path. + + 995. [bug] dig, host, nslookup: using a raw IPv6 address as a + target address should be fatal on a IPv4 only system. + + 994. [func] Treat non-authoritative responses to queries for type + NS as referrals even if the NS records are in the + answer section, because BIND 8 servers incorrectly + send them that way. This is necessary for DNSSEC + validation of the NS records of a secure zone to + succeed when the parent is a BIND 8 server. [RT #1706] + + 993. [func] dig: -v now reports the version. + + 992. [doc] dig: ~/.digrc is now documented. + + 991. [func] Lower UDP refresh timeout messages to level + debug 1. + + 990. [bug] The rndc-confgen man page was not installed. + + 989. [bug] Report filename if $INCLUDE fails for file related + errors. [RT #1736] + + 988. [bug] 'additional-from-auth no;' did not work reliably + in the case of queries answered from the cache. + [RT #1436] + + 987. [bug] "dig -help" didn't show "+[no]stats". + + 986. [bug] "dig +noall" failed to clear stats and command + printing. + + 985. [func] Consider network interfaces to be up iff they have + a nonzero IP address rather than based on the + IFF_UP flag. [RT #1160] + + 984. [bug] Multi-threading should be enabled by default on + Solaris 2.7 and newer, but it wasn't. + + 983. [func] The server now supports generating IXFR difference + sequences for non-dynamic zones by comparing zone + versions, when enabled using the new config + option "ixfr-from-differences". [RT #1727] + + 982. [func] If "memstatistics-file" is set in options the memory + statistics will be written to it. + + 981. [func] The dnssec tools can now take multiple '-r randomfile' + arguments. + + 980. [bug] Incoming zone transfers restarting after an error + could trigger an assertion failure. [RT #1692] + + 979. [func] Incremental master file dumping. dns_master_dumpinc(), + dns_master_dumptostreaminc(), dns_dumpctx_attach(), + dns_dumpctx_detach(), dns_dumpctx_cancel(), + dns_dumpctx_db() and dns_dumpctx_version(). + + 978. [bug] dns_db_attachversion() had an invalid REQUIRE() + condition. + + 977. [bug] Improve "not at top of zone" error message. + + 976. [func] named-checkconf can now test load master zones + (named-checkconf -z). [RT #1468] + + 975. [bug] "max-cache-size default;" as a view option + caused an assertion failure. + + 974. [bug] "max-cache-size unlimited;" as a global option + was not accepted. + + 973. [bug] Failed to log the question name when logging: + "bad zone transfer request: non-authoritative zone + (NOTAUTH)". + + 972. [bug] The file modification time code in zone.c was using the + wrong epoch. [RT #1667] + + 971. [placeholder] + + 970. [func] 'max-journal-size' can now be used to set a target + size for a journal. + + 969. [func] dig now supports the undocumented dig 8 feature + of allowing arbitrary labels, not just dotted + decimal quads, with the -x option. This can be + used to conveniently look up RFC2317 names as in + "dig -x 10.0.0.0-127". [RT #827, #1576, #1598] + + 968. [bug] On win32, the isc_time_now() function was unnecessarily + calling strtime(). [RT #1671] + + 967. [bug] On win32, the link for bindevt was not including the + required resource file to enable the event viewer + to interpret the error messages in the event log, + [RT #1668] + + 966. [placeholder] + + 965. [bug] Including data other than root server NS and A + records in the root hint file could cause a rbtdb + node reference leak. [RT #1581, #1618] + + 964. [func] Warn if data other than root server NS and A records + are found in the root hint file. [RT #1581, #1618] + + 963. [bug] Bad ISC_LANG_ENDDECLS. [RT #1645] + + 962. [bug] libbind: bad "#undef", don't attempt to install + non-existant nlist.h. [RT #1640] + + 961. [bug] Tried to use a IPV6 feature when ISC_PLATFORM_HAVEIPV6 + was not defined. [RT #1482] + + 960. [port] liblwres failed to build on systems with support for + getrrsetbyname() in the OS. [RT #1592] + + 959. [port] On FreeBSD, determine the number of CPUs by calling + sysctlbyname(). [RT #1584] + + 958. [port] ssize_t is not available on all platforms. [RT #1607] + + 957. [bug] sys/select.h inclusion was broken on older platforms. + [RT #1607] + + 956. [bug] ns_g_autorndcfile changed to ns_g_keyfile + in named/win32/os.c due to code changes in + change #953. win32 .make file for rndc-confgen + updated to add include path for os.h header. + + --- 9.2.0rc1 released --- + + 955. [bug] When using views, the zone's class was not being + inherited from the view's class. [RT #1583] + + 954. [bug] When requesting AXFRs or IXFRs using dig, host, or + nslookup, the RD bit should not be set as zone + transfers are inherently non-recursive. [RT #1575] + + 953. [func] The /var/run/named.key file from change #843 + has been replaced by /etc/rndc.key. Both + named and rndc will look for this file and use + it to configure a default control channel key + if not already configured using a different + method (rndc.conf / controls). Unlike + named.key, rndc.key is not created automatically; + it must be created by manually running + "rndc-confgen -a". + + 952. [bug] The server required manual intervention to serve the + affected zones if it died between creating a journal + and committing the first change to it. + + 951. [bug] CFLAGS was not passed to the linker when + linking some of the test programs under + bin/tests. [RT #1555]. + + 950. [bug] Explicit TTLs did not properly override $TTL + due to a bug in change 834. [RT #1558] + + 949. [bug] host was unable to print records larger than 512 + bytes. [RT #1557] + + --- 9.2.0b2 released --- + + 948. [port] Integrated support for building on Windows NT / + Windows 2000. + + 947. [bug] dns_rdata_soa_t had a badly named element "mname" which + was really the RNAME field from RFC1035. To avoid + confusion and silent errors that would occur it the + "origin" and "mname" elements were given their correct + names "mname" and "rname" respectively, the "mname" + element is renamed to "contact". + + 946. [cleanup] doc/misc/options is now machine-generated from the + configuration parser syntax tables, and therefore + more likely to be correct. + + 945. [func] Add the new view-specific options + "match-destinations" and "match-recursive-only". + + 944. [func] Check for expired signatures on load. + + 943. [bug] The server could crash when receiving a command + via rndc if the configuration file listed only + nonexistent keys in the controls statement. [RT #1530] + + 942. [port] libbind: GETNETBYADDR_ADDR_T was not correctly + defined on some platforms. + + 941. [bug] The configuration checker crashed if a slave + zone didn't contain a masters statement. [RT #1514] + + 940. [bug] Double zone locking failure on error path. [RT #1510] + + --- 9.2.0b1 released --- + + 939. [port] Add the --disable-linux-caps option to configure for + systems that manage capabilities outside of named. + [RT #1503] + + 938. [placeholder] + + 937. [bug] A race when shutting down a zone could trigger a + INSIST() failure. [RT #1034] + + 936. [func] Warn about IPv4 addresses that are not complete + dotted quads. [RT #1084] + + 935. [bug] inet_pton failed to reject leading zeros. + + 934. [port] Deal with systems where accept() spuriously returns + ECONNRESET. + + 933. [bug] configure failed doing libbind on platforms not + supported by BIND 8. [RT #1496] + + --- 9.2.0a3 released --- + + 932. [bug] Use INSTALL_SCRIPT, not INSTALL_PROGRAM, + when installing isc-config.sh. + [RT #198, #1466] + + 931. [bug] The controls statement only attempted to verify + messages using the first key in the key list. + (9.2.0a1/a2 only). + + 930. [func] Query performance testing tool added as + contrib/queryperf. + + 929. [placeholder] + + 928. [bug] nsupdate would send empty update packets if the + send (or empty line) command was run after + another send but before any new updates or + prerequisites were specified. It should simply + ignore this command. + + 927. [bug] Don't hold the zone lock for the entire dump to disk. + [RT #1423] + + 926. [bug] The resolver could deadlock with the ADB when + shutting down (multi-threaded builds only). + [RT #1324] + + 925. [cleanup] Remove openssl from the distribution; require that + --with-openssl be specified if DNSSEC is needed. + + 924. [port] Extend support for pre-RFC2133 IPv6 implementation. + [RT #987] + + 923. [bug] Multiline TSIG secrets (and other multiline strings) + were not accepted in named.conf. [RT #1469] + + 922. [func] Added two new lwres_getrrsetbyname() result codes, + ERR_NONAME and ERR_NODATA. + + 921. [bug] lwres returned an incorrect error code if it received + a truncated message. + + 920. [func] Increase the lwres receive buffer size to 16K. + [RT #1451] + + 919. [placeholder] + + 918. [func] In nsupdate, TSIG errors are no longer treated as + fatal errors. + + 917. [func] New nsupdate command 'key', allowing TSIG keys to + be specified in the nsupdate command stream rather + than the command line. + + 916. [bug] Specifying type ixfr to dig without specifying + a serial number failed in unexpected ways. + + 915. [func] The named-checkconf and named-checkzone programs + now have a '-v' option for printing their version. + [RT #1151] + + 914. [bug] Global 'server' statements were rejected when + using views, even though they were accepted + in 9.1. [RT #1368] + + 913. [bug] Cache cleaning was not sufficiently aggressive. + [RT #1441, #1444] + + 912. [bug] Attempts to set the 'additional-from-cache' or + 'additional-from-auth' option to 'no' in a + server with recursion enabled will now + be ignored and cause a warning message. + [RT #1145] + + 911. [placeholder] + + 910. [port] Some pre-RFC2133 IPv6 implementations do not define + IN6ADDR_ANY_INIT. [RT #1416] + + 909. [placeholder] + + 908. [func] New program, rndc-confgen, to simplify setting up rndc. + + 907. [func] The ability to get entropy from either the + random device, a user-provided file or from + the keyboard was migrated from the DNSSEC tools + to libisc as isc_entropy_usebestsource(). + + 906. [port] Separated the system independent portion of + lib/isc/unix/entropy.c into lib/isc/entropy.c + and added lib/isc/win32/entropy.c. + + 905. [bug] Configuring a forward "zone" for the root domain + did not work. [RT #1418] + + 904. [bug] The server would leak memory if attempting to use + an expired TSIG key. [RT #1406] + + 903. [bug] dig should not crash when receiving a TCP packet + of length 0. + + 902. [bug] The -d option was ignored if both -t and -g were also + specified. + + 901. [placeholder] + + 900. [bug] A config.guess update changed the system identification + string of FreeBSD systems; configure and + bin/tests/system/ifconfig.sh now recognize the new + string. + + --- 9.2.0a2 released --- + + 899. [bug] lib/dns/soa.c failed to compile on many platforms + due to inappropriate use of a void value. + [RT #1372, #1373, #1386, #1387, #1395] + + 898. [bug] "dig" failed to set a nonzero exit status + on UDP query timeout. [RT #1323] + + 897. [bug] A config.guess update changed the system identification + string of UnixWare systems; configure now recognizes + the new string. + + 896. [bug] If a configuration file is set on named's command line + and it has a relative pathname, the current directory + (after any possible jailing resulting from named -t) + will be prepended to it so that reloading works + properly even when a directory option is present. + + 895. [func] New function, isc_dir_current(), akin to POSIX's + getcwd(). + + 894. [bug] When using the DNSSEC tools, a message intended to warn + when the keyboard was being used because of the lack + of a suitable random device was not being printed. + + 893. [func] Removed isc_file_test() and added isc_file_exists() + for the basic functionality that was being added + with isc_file_test(). + + 892. [placeholder] + + 891. [bug] Return an error when a SIG(0) signed response to + an unsigned query is seen. This should actually + do the verification, but it's not currently + possible. [RT #1391] + + 890. [cleanup] The man pages no longer require the mandoc macros + and should now format cleanly using most versions of + nroff, and HTML versions of the man pages have been + added. Both are generated from DocBook source. + + 889. [port] Eliminated blank lines before .TH in nroff man + pages since they cause problems with some versions + of nroff. [RT #1390] + + 888. [bug] Don't die when using TKEY to delete a nonexistent + TSIG key. [RT #1392] + + 887. [port] Detect broken compilers that can't call static + functions from inline functions. [RT #1212] + + 886. [placeholder] + + 885. [placeholder] + + 884. [placeholder] + + 883. [placeholder] + + 882. [placeholder] + + 881. [placeholder] + + 880. [placeholder] + + 879. [placeholder] + + 878. [placeholder] + + 877. [placeholder] + + 876. [placeholder] + + 875. [placeholder] + + 874. [placeholder] + + 873. [placeholder] + + 872. [placeholder] + + 871. [placeholder] + + 870. [placeholder] + + 869. [placeholder] + + 868. [placeholder] + + 867. [placeholder] + + 866. [func] Close debug only file channels when debug is set to + zero. [RT #1246] + + 865. [bug] The new configuration parser did not allow + the optional debug level in a "severity debug" + clause of a logging channel to be omitted. + This is now allowed and treated as "severity + debug 1;" like it does in BIND 8.2.4, not as + "severity debug 0;" like it did in BIND 9.1. + [RT #1367] + + 864. [cleanup] Multi-threading is now enabled by default on + OSF1, Solaris 2.7 and newer, AIX, IRIX, and HP-UX. + + 863. [bug] If an error occurred while an outgoing zone transfer + was starting up, the server could access a domain + name that had already been freed when logging a + message saying that the transfer was starting. + [RT #1383] + + 862. [bug] Use after realloc(), non portable pointer arithmetic in + grmerge(). + + 861. [port] Add support for Mac OS X, by making it equivalent + to Darwin. This was derived from the config.guess + file shipped with Mac OS X. [RT #1355] + + 860. [func] Drop cross class glue in zone transfers. + + 859. [bug] Cache cleaning now won't swamp the CPU if there + is a persistent over limit condition. + + 858. [func] isc_mem_setwater() no longer requires that when the + callback function is non-NULL then its hi_water + argument must be greater than its lo_water argument + (they can now be equal) or that they be non-zero. + + 857. [cleanup] Use ISC_MAGIC() to define all magic numbers for + structs, for our friends in EBCDIC-land. + + 856. [func] Allow partial rdatasets to be returned in answer and + authority sections to help non-TCP capable clients + recover from truncation. [RT #1301] + + 855. [bug] Stop spurious "using RFC 1035 TTL semantics" warnings. + + 854. [bug] The config parser didn't properly handle config + options that were specified in units of time other + than seconds. [RT #1372] + + 853. [bug] configure_view_acl() failed to detach existing acls. + [RT #1374] + + 852. [bug] Handle responses from servers which do not know + about IXFR. + + 851. [cleanup] The obsolete support-ixfr option was not properly + ignored. + + --- 9.2.0a1 released --- + + 850. [bug] dns_rbt_findnode() would not find nodes that were + split on a bitstring label somewhere other than in + the last label of the node. [RT #1351] + + 849. [func] will ensure INADDR_LOOPBACK is defined. + + 848. [func] A minimum max-cache-size of two megabytes is enforced + by the cache cleaner. + + 847. [func] Added isc_file_test(), which currently only has + some very basic functionality to test for the + existence of a file, whether a pathname is absolute, + or whether a pathname is the fundamental representation + of the current directory. It is intended that this + function can be expanded to test other things a + programmer might want to know about a file. + + 846. [func] A non-zero 'param' to dst_key_generate() when making an + hmac-md5 key means that good entropy is not required. + + 845. [bug] The access rights on the public file of a symmetric + key are now restricted as soon as the file is opened, + rather than after it has been written and closed. + + 844. [func] will ensure INADDR_LOOPBACK is defined, + just as does. + + 843. [func] If no controls statement is present in named.conf, + or if any inet phrase of a controls statement is + lacking a keys clause, then a key will be automatically + generated by named and an rndc.conf-style file + named named.key will be written that uses it. rndc + will use this file only if its normal configuration + file, or one provided on the command line, does not + exist. + + 842. [func] 'rndc flush' now takes an optional view. + + 841. [bug] When sdb modules were not declared threadsafe, their + create and destroy functions were not serialized. + + 840. [bug] The config file parser could print the wrong file + name if an error was detected after an included file + was parsed. [RT #1353] + + 839. [func] Dump packets for which there was no view or that the + class could not be determined to category "unmatched". + + 838. [port] UnixWare 7.x.x is now suported by + bin/tests/system/ifconfig.sh. + + 837. [cleanup] Multi-threading is now enabled by default only on + OSF1, Solaris 2.7 and newer, and AIX. + + 836. [func] Upgraded libtool to 1.4. + + 835. [bug] The dispatcher could enter a busy loop if + it got an I/O error receiving on a UDP socket. + [RT #1293] + + 834. [func] Accept (but warn about) master files beginning with + an SOA record without an explicit TTL field and + lacking a $TTL directive, by using the SOA MINTTL + as a default TTL. This is for backwards compatibility + with old versions of BIND 8, which accepted such + files without warning although they are illegal + according to RFC1035. + + 833. [cleanup] Moved dns_soa_*() from to + , and extended them to support + all the integer-valued fields of the SOA RR. + + 832. [bug] The default location for named.conf in named-checkconf + should depend on --sysconfdir like it does in named. + [RT #1258] + + 831. [placeholder] + + 830. [func] Implement 'rndc status'. + + 829. [bug] The DNS_R_ZONECUT result code should only be returned + when an ANY query is made with DNS_DBFIND_GLUEOK set. + In all other ANY query cases, returning the delegation + is better. + + 828. [bug] The errno value from recvfrom() could be overwritten + by logging code. [RT #1293] + + 827. [bug] When an IXFR protocol error occurs, the slave + should retry with AXFR. + + 826. [bug] Some IXFR protocol errors were not detected. + + 825. [bug] zone.c:ns_query() detached from the wrong zone + reference. [RT #1264] + + 824. [bug] Correct line numbers reported by dns_master_load(). + [RT #1263] + + 823. [func] The output of "dig -h" now goes to stdout so that it + can easily be piped through "more". [RT #1254] + + 822. [bug] Sending nxrrset prerequisites would crash nsupdate. + [RT #1248] + + 821. [bug] The program name used when logging to syslog should + be stripped of leading path components. + [RT #1178, #1232] + + 820. [bug] Name server address lookups failed to follow + A6 chains into the glue of local authoritative + zones. + + 819. [bug] In certain cases, the resolver's attempts to + restart an address lookup at the root could cause + the fetch to deadlock (with itself) instead of + restarting. [RT #1225] + + 818. [bug] Certain pathological responses to ANY queries could + cause an assertion failure. [RT #1218] + + 817. [func] Adjust timeouts for dialup zone queries. + + 816. [bug] Report potential problems with log file accessibility + at configuration time, since such problems can't + reliably be reported at the time they actually occur. + + 815. [bug] If a log file was specified with a path separator + character (i.e. "/") in its name and the directory + did not exist, the log file's name was treated as + though it were the directory name. [RT #1189] + + 814. [bug] Socket objects left over from accept() failures + were incorrectly destroyed, causing corruption + of socket manager data structures. + + 813. [bug] File descriptors exceeding FD_SETSIZE were handled + badly. [RT #1192] + + 812. [bug] dig sometimes printed incomplete IXFR responses + due to an uninitialized variable. [RT #1188] + + 811. [bug] Parentheses were not quoted in zone dumps. [RT #1194] + + 810. [bug] The signer name in SIG records was not properly + down-cased when signing/verifying records. [RT #1186] + + 809. [bug] Configuring a non-local address as a transfer-source + could cause an assertion failure during load. + + 808. [func] Add 'rndc flush' to flush the server's cache. + + 807. [bug] When setting up TCP connections for incoming zone + transfers, the transfer-source port was not + ignored like it should be. + + 806. [bug] DNS_R_SEENINCLUDE was failing to propagate back up + the calling stack to the zone maintenance level, + causing zones to not reload when an included file was + touched but the top-level zone file was not. + + 805. [bug] When using "forward only", missing root hints should + not cause queries to fail. [RT #1143] + + 804. [bug] Attempting to obtain entropy could fail in some + situations. This would be most common on systems + with user-space threads. [RT #1131] + + 803. [bug] Treat all SIG queries as if they have the CD bit set, + otherwise no data will be returned [RT #749] + + 802. [bug] DNSSEC key tags were computed incorrectly in almost + all cases. [RT #1146] + + 801. [bug] nsupdate should treat lines beginning with ';' as + comments. [RT #1139] + + 800. [bug] dnssec-signzone produced incorrect statistics for + large zones. [RT #1133] + + 799. [bug] The ADB didn't find AAAA glue in a zone unless A6 + glue was also present. + + 798. [bug] nsupdate should be able to reject bad input lines + and continue. [RT #1130] + + 797. [func] Issue a warning if the 'directory' option contains + a relative path. [RT #269] + + 796. [func] When a size limit is associated with a log file, + only roll it when the size is reached, not every + time the log file is opened. [RT #1096] + + 795. [func] Add the +multiline option to dig. [RT #1095] + + 794. [func] Implement the "port" and "default-port" statements + in rndc.conf. + + 793. [cleanup] The DNSSEC tools could create filenames that were + illegal or contained shell meta-characters. They + now use a different text encoding of names that + doesn't have these problems. [RT #1101] + + 792. [cleanup] Replace the OMAPI command channel protocol with a + simpler one. + + 791. [bug] The command channel now works over IPv6. + + 790. [bug] Wildcards created using dynamic update or IXFR + could fail to match. [RT #1111] + + 789. [bug] The "localhost" and "localnets" ACLs did not match + when used as the second element of a two-element + sortlist item. + + 788. [func] Add the "match-mapped-addresses" option, which + causes IPv6 v4mapped addresses to be treated as + IPv4 addresses for the purpose of acl matching. + + 787. [bug] The DNSSEC tools failed to downcase domain + names when mapping them into file names. + + 786. [bug] When DNSSEC signing/verifying data, owner names were + not properly down-cased. + + 785. [bug] A race condition in the resolver could cause + an assertion failure. [RT #673, #872, #1048] + + 784. [bug] nsupdate and other programs would not quit properly + if some signals were blocked by the caller. [RT #1081] + + 783. [bug] Following CNAMEs could cause an assertion failure + when either using an sdb database or under very + rare conditions. + + 782. [func] Implement the "serial-query-rate" option. + + 781. [func] Avoid error packet loops by dropping duplicate FORMERR + responses. [RT #1006] + + 780. [bug] Error handling code dealing with out of memory or + other rare errors could lead to assertion failures + by calling functions on uninitialized names. [RT #1065] + + 779. [func] Added the "minimal-responses" option. + + 778. [bug] When starting cache cleaning, cleaning_timer_action() + returned without first pausing the iterator, which + could cause deadlock. [RT #998] + + 777. [bug] An empty forwarders list in a zone failed to override + global forwarders. [RT #995] + + 776. [func] Improved error reporting in denied messages. [RT #252] + + 775. [placeholder] + + 774. [func] max-cache-size is implemented. + + 773. [func] Added isc_rwlock_trylock() to attempt to lock without + blocking. + + 772. [bug] Owner names could be incorrectly omitted from cache + dumps in the presence of negative caching entries. + [RT #991] + + 771. [cleanup] TSIG errors related to unsynchronized clocks + are logged better. [RT #919] + + 770. [func] Add the "edns yes_or_no" statement to the server + clause. [RT #524] + + 769. [func] Improved error reporting when parsing rdata. [RT #740] + + 768. [bug] The server did not emit an SOA when a CNAME + or DNAME chain ended in NXDOMAIN in an + authoritative zone. + + 767. [placeholder] + + 766. [bug] A few cases in query_find() could leak fname. + This would trigger the mpctx->allocated == 0 + assertion when the server exited. + [RT #739, #776, #798, #812, #818, #821, #845, + #892, #935, #966] + + 765. [func] ACL names are once again case insensitive, like + in BIND 8. [RT #252] + + 764. [func] Configuration files now allow "include" directives + in more places, such as inside the "view" statement. + [RT #377, #728, #860] + + 763. [func] Configuration files no longer have reserved words. + [RT #731, #753] + + 762. [cleanup] The named.conf and rndc.conf file parsers have + been completely rewritten. + + 761. [bug] _REENTRANT was still defined when building with + --disable-threads. + + 760. [contrib] Significant enhancements to the pgsql sdb driver. + + 759. [bug] The resolver didn't turn off "avoid fetches" mode + when restarting, possibly causing resolution + to fail when it should not. This bug only affected + platforms which support both IPv4 and IPv6. [RT #927] + + 758. [bug] The "avoid fetches" code did not treat negative + cache entries correctly, causing fetches that would + be useful to be avoided. This bug only affected + platforms which support both IPv4 and IPv6. [RT #927] + + 757. [func] Log zone transfers. + + 756. [bug] dns_zone_load() could "return" success when no master + file was configured. + + 755. [bug] Fix incorrectly formatted log messages in zone.c. + + 754. [bug] Certain failure conditions sending UDP packets + could cause the server to retry the transmission + indefinitely. [RT #902] + + 753. [bug] dig, host, and nslookup would fail to contact a + remote server if getaddrinfo() returned an IPv6 + address on a system that doesn't support IPv6. + [RT #917] + + 752. [func] Correct bad tv_usec elements returned by + gettimeofday(). + + 751. [func] Log successful zone loads / transfers. [RT #898] + + 750. [bug] A query should not match a DNAME whose trust level + is pending. [RT #916] + + 749. [bug] When a query matched a DNAME in a secure zone, the + server did not return the signature of the DNAME. + [RT #915] + + 748. [doc] List supported RFCs in doc/misc/rfc-compliance. + [RT #781] + + 747. [bug] The code to determine whether an IXFR was possible + did not properly check for a database that could + not have a journal. [RT #865, #908] + + 746. [bug] The sdb didn't clone rdatasets properly, causing + a crash when the server followed delegations. [RT #905] + + 745. [func] Report the owner name of records that fail + semantic checks while loading. + + 744. [bug] When returning DNS_R_CNAME or DNS_R_DNAME as the + result of an ANY or SIG query, the resolver failed + to setup the return event's rdatasets, causing an + assertion failure in the query code. [RT #881] + + 743. [bug] Receiving a large number of certain malformed + answers could cause named to stop responding. + [RT #861] + + 742. [placeholder] + + 741. [port] Support openssl-engine. [RT #709] + + 740. [port] Handle openssl library mismatches slightly better. + + 739. [port] Look for /dev/random in configure, rather than + assuming it will be there for only a predefined + set of OSes. + + 738. [bug] If a non-threadsafe sdb driver supported AXFR and + received an AXFR request, it would deadlock or die + with an assertion failure. [RT #852] + + 737. [port] stdtime.c failed to compile on certain platforms. + + 736. [func] New functions isc_task_{begin,end}exclusive(). + + 735. [doc] Add BIND 4 migration notes. + + 734. [bug] An attempt to re-lock the zone lock could occur if + the server was shutdown during a zone transfer. + [RT #830] + + 733. [bug] Reference counts of dns_acl_t objects need to be + locked but were not. [RT #801, #821] + + 732. [bug] Glue with 0 TTL could also cause SERVFAIL. [RT #828] + + 731. [bug] Certain zone errors could cause named-checkzone to + fail ungracefully. [RT #819] + + 730. [bug] lwres_getaddrinfo() returns the correct result when + it fails to contact a server. [RT #768] + + 729. [port] pthread_setconcurrency() needs to be called on Solaris. + + 728. [bug] Fix comment processing on master file directives. + [RT# 757] + + 727. [port] Work around OS bug where accept() succeeds but + fails to fill in the peer address of the accepted + connection, by treating it as an error rather than + an assertion failure. [RT #809] + + 726. [func] Implement the "trace" and "notrace" commands in rndc. + + 725. [bug] Installing man pages could fail. + + 724. [func] New libisc functions isc_netaddr_any(), + isc_netaddr_any6(). + + 723. [bug] Referrals whose NS RRs had a 0 TTL caused the resolver + to return DNS_R_SERVFAIL. [RT #783] + + 722. [func] Allow incremental loads to be canceled. + + 721. [cleanup] Load manager and dns_master_loadfilequota() are no + more. + + 720. [bug] Server could enter infinite loop in + dispatch.c:do_cancel(). [RT #733] + + 719. [bug] Rapid reloads could trigger an assertion failure. + [RT #743, #763] + + 718. [cleanup] "internal" is no longer a reserved word in named.conf. + [RT #753, #731] + + 717. [bug] Certain TKEY processing failure modes could + reference an uninitialized variable, causing the + server to crash. [RT #750] + + 716. [bug] The first line of a $INCLUDE master file was lost if + an origin was specified. [RT #744] + + 715. [bug] Resolving some A6 chains could cause an assertion + failure in adb.c. [RT #738] + + 714. [bug] Preserve interval timers across reloads unless changed. + [RT# 729] + + 713. [func] named-checkconf takes '-t directory' similar to named. + [RT #726] + + 712. [bug] Sending a large signed update message caused an + assertion failure. [RT #718] + + 711. [bug] The libisc and liblwres implementations of + inet_ntop contained an off by one error. + + 710. [func] The forwarders statement now takes an optional + port. [RT #418] + + 709. [bug] ANY or SIG queries for data with a TTL of 0 + would return SERVFAIL. [RT #620] + + 708. [bug] When building with --with-openssl, the openssl headers + included with BIND 9 should not be used. [RT #702] + + 707. [func] The "filename" argument to named-checkzone is no + longer optional, to reduce confusion. [RT #612] + + 706. [bug] Zones with an explicit "allow-update { none; };" + were considered dynamic and therefore not reloaded + on SIGHUP or "rndc reload". + + 705. [port] Work out resource limit type for use where rlim_t is + not available. [RT #695] + + 704. [port] RLIMIT_NOFILE is not available on all platforms. + [RT #695] + + 703. [port] sys/select.h is needed on older platforms. [RT #695] + + 702. [func] If the address 0.0.0.0 is seen in resolv.conf, + use 127.0.0.1 instead. [RT #693] + + 701. [func] Root hints are now fully optional. Class IN + views use compiled-in hints by default, as + before. Non-IN views with no root hints now + provide authoritative service but not recursion. + A warning is logged if a view has neither root + hints nor authoritative data for the root. [RT #696] + + 700. [bug] $GENERATE range check was wrong. [RT #688] + + 699. [bug] The lexer mishandled empty quoted strings. [RT #694] + + 698. [bug] Aborting nsupdate with ^C would lead to several + race conditions. + + 697. [bug] nsupdate was not compatible with the undocumented + BIND 8 behavior of ignoring TTLs in "update delete" + commands. [RT #693] + + 696. [bug] lwresd would die with an assertion failure when passed + a zero-length name. [RT #692] + + 695. [bug] If the resolver attempted to query a blackholed or + bogus server, the resolution would fail immediately. + + 694. [bug] $GENERATE did not produce the last entry. + [RT #682, #683] + + 693. [bug] An empty lwres statement in named.conf caused + the server to crash while loading. + + 692. [bug] Deal with systems that have getaddrinfo() but not + gai_strerror(). [RT #679] + + 691. [bug] Configuring per-view forwarders caused an assertion + failure. [RT #675, #734] + + 690. [func] $GENERATE now supports DNAME. [RT #654] + + 689. [doc] man pages are now installed. [RT #210] + + 688. [func] "make tags" now works on systems with the + "Exuberant Ctags" etags. + + 687. [bug] Only say we have IPv6, with sufficient functionality, + if it has actually been tested. [RT #586] + + 686. [bug] dig and nslookup can now be properly aborted during + blocking operations. [RT #568] + + 685. [bug] nslookup should use the search list/domain options + from resolv.conf by default. [RT #405, #630] + + 684. [bug] Memory leak with view forwarders. [RT #656] + + 683. [bug] File descriptor leak in isc_lex_openfile(). + + 682. [bug] nslookup displayed SOA records incorrectly. [RT #665] + + 681. [bug] $GENERATE specifying output format was broken. [RT #653] + + 680. [bug] dns_rdata_fromstruct() mishandled options bigger + than 255 octets. + + 679. [bug] $INCLUDE could leak memory and file descriptors on + reload. [RT #639] + + 678. [bug] "transfer-format one-answer;" could trigger an assertion + failure. [RT #646] + + 677. [bug] dnssec-signzone would occasionally use the wrong ttl + for database operations and fail. [RT #643] + + 676. [bug] Log messages about lame servers to category + 'lame-servers' rather than 'resolver', so as not + to be gratuitously incompatible with BIND 8. + + 675. [bug] TKEY queries could cause the server to leak + memory. + + 674. [func] Allow messages to be TSIG signed / verified using + a offset from the current time. + + 673. [func] The server can now convert RFC1886-style recursive + lookup requests into RFC2874-style lookups, when + enabled using the new option "allow-v6-synthesis". + + 672. [bug] The wrong time was in the "time signed" field when + replying with BADTIME error. + + 671. [bug] The message code was failing to parse a message with + no question section and a TSIG record. [RT #628] + + 670. [bug] The lwres replacements for getaddrinfo and + getipnodebyname didn't properly check for the + existence of the sockaddr sa_len field. + + 669. [bug] dnssec-keygen now makes the public key file + non-world-readable for symmetric keys. [RT #403] + + 668. [func] named-checkzone now reports multiple errors in master + files. + + 667. [bug] On Linux, running named with the -u option and a + non-world-readable configuration file didn't work. + [RT #626] + + 666. [bug] If a request sent by dig is longer than 512 bytes, + use TCP. + + 665. [bug] Signed responses were not sent when the size of the + TSIG + question exceeded the maximum message size. + [RT #628] + + 664. [bug] The t_tasks and t_timers module tests are now skipped + when building without threads, since they require + threads. + + 663. [func] Accept a size_spec, not just an integer, in the + (unimplemented and ignored) max-ixfr-log-size option + for compatibility with recent versions of BIND 8. + [RT #613] + + 662. [bug] dns_rdata_fromtext() failed to log certain errors. + + 661. [bug] Certain UDP IXFR requests caused an assertion failure + (mpctx->allocated == 0). [RT #355, #394, #623] + + 660. [port] Detect multiple CPUs on HP-UX and IRIX. + + 659. [performance] Rewrite the name compression code to be much faster. + + 658. [cleanup] Remove all vestiges of 16 bit global compression. + + 657. [bug] When a listen-on statement in an lwres block does not + specify a port, use 921, not 53. Also update the + listen-on documentation. [RT #616] + + 656. [func] Treat an unescaped newline in a quoted string as + an error. This means that TXT records with missing + close quotes should have meaningful errors printed. + + 655. [bug] Improve error reporting on unexpected eof when loading + zones. [RT #611] + + 654. [bug] Origin was being forgotten in TCP retries in dig. + [RT #574] + + 653. [bug] +defname option in dig was reversed in sense. + [RT #549] + + 652. [bug] zone_saveunique() did not report the new name. + + 651. [func] The AD bit in responses now has the meaning + specified in . + + 650. [bug] SIG(0) records were being generated and verified + incorrectly. [RT #606] + + 649. [bug] It was possible to join to an already running fctx + after it had "cloned" its events, but before it sent + them. In this case, the event of the newly joined + fetch would not contain the answer, and would + trigger the INSIST() in fctx_sendevents(). In + BIND 9.0, this bug did not trigger an INSIST(), but + caused the fetch to fail with a SERVFAIL result. + [RT #588, #597, #605, #607] + + 648. [port] Add support for pre-RFC2133 IPv6 implementations. + + 647. [bug] Resolver queries sent after following multiple + referrals had excessively long retransmission + timeouts due to incorrectly counting the referrals + as "restarts". + + 646. [bug] The UnixWare ISC_PLATFORM_FIXIN6INADDR fix in isc/net.h + didn't _cleanly_ fix the problem it was trying to fix. + + 645. [port] BSD/OS 3.0 needs pthread_init(). [RT #603] + + 644. [bug] #622 needed more work. [RT #562] + + 643. [bug] xfrin error messages made more verbose, added class + of the zone. [RT# 599] + + 642. [bug] Break the exit_check() race in the zone module. + [RT #598] + + --- 9.1.0b2 released --- + + 641. [bug] $GENERATE caused a uninitialized link to be used. + [RT #595] + + 640. [bug] Memory leak in error path could cause + "mpctx->allocated == 0" failure. [RT #584] + + 639. [bug] Reading entropy from the keyboard would sometimes fail. + [RT #591] + + 638. [port] lib/isc/random.c needed to explicitly include time.h + to get a prototype for time() when pthreads was not + being used. [RT #592] + + 637. [port] Use isc_u?int64_t instead of (unsigned) long long in + lib/isc/print.c. Also allow lib/isc/print.c to + be compiled even if the platform does not need it. + [RT #592] + + 636. [port] Shut up MSVC++ about a possible loss of precision + in the ISC__BUFFER_PUTUINT*() macros. [RT #592] + + 635. [bug] Reloading a server with a configured blackhole list + would cause an assertion. [RT #590] + + 634. [bug] A log file will completely stop being written when + it reaches the maximum size in all cases, not just + when versioning is also enabled. [RT #570] + + 633. [port] Cope with rlim_t missing on BSD/OS systems. [RT #575] + + 632. [bug] The index array of the journal file was + corrupted as it was written to disk. + + 631. [port] Build without thread support on systems without + pthreads. + + 630. [bug] Locking failure in zone code. [RT #582] + + 629. [bug] 9.1.0b1 dereferenced a null pointer and crashed + when responding to a UDP IXFR request. + + 628. [bug] If the root hints contained only AAAA addresses, + named would be unable to perform resolution. + + 627. [bug] The EDNS0 blackhole detection code of change 324 + waited for three retransmissions to each server, + which takes much too long when a domain has many + name servers and all of them drop EDNS0 queries. + Now we retry without EDNS0 after three consecutive + timeouts, even if they are all from different + servers. [RT #143] + + 626. [bug] The lightweight resolver daemon no longer crashes + when asked for a SIG rrset. [RT #558] + + 625. [func] Zones now inherit their class from the enclosing view. + + 624. [bug] The zone object could get timer events after it had + been destroyed, causing a server crash. [RT #571] + + 623. [func] Added "named-checkconf" and "named-checkzone" program + for syntax checking named.conf files and zone files, + respectively. + + 622. [bug] A canceled request could be destroyed before + dns_request_destroy() was called. [RT #562] + + 621. [port] Disable IPv6 at runtime if IPv6 sockets are unusable. + This mostly affects Red Hat Linux 7.0, which has + conflicts between libc and the kernel. + + 620. [bug] dns_master_load*inc() now require 'task' and 'load' + to be non-null. Also 'done' will not be called if + dns_master_load*inc() fails immediately. [RT #565] + + 619. [placeholder] + + 618. [bug] Queries to a signed zone could sometimes cause + an assertion failure. + + 617. [bug] When using dynamic update to add a new RR to an + existing RRset with a different TTL, the journal + entries generated from the update did not include + explicit deletions and re-additions of the existing + RRs to update their TTL to the new value. + + 616. [func] dnssec-signzone -t output now includes performance + statistics. + + 615. [bug] dnssec-signzone did not like child keysets signed + by multiple keys. + + 614. [bug] Checks for uninitialized link fields were prone + to false positives, causing assertion failures. + The checks are now disabled by default and may + be re-enabled by defining ISC_LIST_CHECKINIT. + + 613. [bug] "rndc reload zone" now reloads primary zones. + It previously only updated slave and stub zones, + if an SOA query indicated an out of date serial. + + 612. [cleanup] Shutup a ridiculously noisy HP-UX compiler that + complains relentlessly about how its treatment + of 'const' has changed as well as how casting + sometimes tightens alignment constraints. + + 611. [func] allow-notify can be used to permit processing of + notify messages from hosts other than a slave's + masters. + + 610. [func] rndc dumpdb is now supported. + + 609. [bug] getrrsetbyname() would crash lwresd if the server + found more SIGs than answers. [RT #554] + + 608. [func] dnssec-signzone now adds a comment to the zone + with the time the file was signed. + + 607. [bug] nsupdate would fail if it encountered a CNAME or + DNAME in a response to an SOA query. [RT #515] + + 606. [bug] Compiling with --disable-threads failed due + to isc_thread_self() being incorrectly defined + as an integer rather than a function. + + 605. [func] New function isc_lex_getlasttokentext(). + + 604. [bug] The named.conf parser could print incorrect line + numbers when long comments were present. + + 603. [bug] Make dig handle multiple types or classes on the same + query more correctly. + + 602. [func] Cope automatically with UnixWare's broken + IN6_IS_ADDR_* macros. [RT #539] + + 601. [func] Return a non-zero exit code if an update fails + in nsupdate. + + 600. [bug] Reverse lookups sometimes failed in dig, etc... + + 599. [func] Added four new functions to the libisc log API to + support i18n messages. isc_log_iwrite(), + isc_log_ivwrite(), isc_log_iwrite1() and + isc_log_ivwrite1() were added. + + 598. [bug] An update-policy statement would cause the server + to assert while loading. [RT #536] + + 597. [func] dnssec-signzone is now multi-threaded. + + 596. [bug] DNS_RDATASLAB_FORCE and DNS_RDATASLAB_EXACT are + not mutually exclusive. + + 595. [port] On Linux 2.2, socket() returns EINVAL when it + should return EAFNOSUPPORT. Work around this. + [RT #531] + + 594. [func] sdb drivers are now assumed to not be thread-safe + unless the DNS_SDBFLAG_THREADSAFE flag is supplied. + + 593. [bug] If a secure zone was missing all its NXTs and + a dynamic update was attempted, the server entered + an infinite loop. + + 592. [bug] The sig-validity-interval option now specifies a + number of days, not seconds. This matches the + documentation. [RT #529] + + --- 9.1.0b1 released --- + + 591. [bug] Work around non-reentrancy in openssl by disabling + pre-computation in keys. + + 590. [doc] There are now man pages for the lwres library in + doc/man/lwres. + + 589. [bug] The server could deadlock if a zone was updated + while being transferred out. + + 588. [bug] ctx->in_use was not being correctly initialized when + when pushing a file for $INCLUDE. [RT #523] + + 587. [func] A warning is now printed if the "allow-update" + option allows updates based on the source IP + address, to alert users to the fact that this + is insecure and becoming increasingly so as + servers capable of update forwarding are being + deployed. + + 586. [bug] multiple views with the same name were fatal. [RT #516] + + 585. [func] dns_db_addrdataset() and and dns_rdataslab_merge() + now support 'exact' additions in a similar manner to + dns_db_subtractrdataset() and dns_rdataslab_subtract(). + + 584. [func] You can now say 'notify explicit'; to suppress + notification of the servers listed in NS records + and notify only those servers listed in the + 'also-notify' option. + + 583. [func] "rndc querylog" will now toggle logging of + queries, like "ndc querylog" in BIND 8. + + 582. [bug] dns_zone_idetach() failed to lock the zone. + [RT #199, #463] + + 581. [bug] log severity was not being correctly processed. + [RT #485] + + 580. [func] Ignore trailing garbage on incoming DNS packets, + for interoperability with broken server + implementations. [RT #491] + + 579. [bug] nsupdate did not take a filename to read update from. + [RT #492] + + 578. [func] New config option "notify-source", to specify the + source address for notify messages. + + 577. [func] Log illegal RDATA combinations. e.g. multiple + singleton types, cname and other data. + + 576. [doc] isc_log_create() description did not match reality. + + 575. [bug] isc_log_create() was not setting internal state + correctly to reflect the default channels created. + + 574. [bug] TSIG signed queries sent by the resolver would fail to + have their responses validated and would leak memory. + + 573. [bug] The journal files of IXFRed slave zones were + inadvertently discarded on server reload, causing + "journal out of sync with zone" errors on subsequent + reloads. [RT #482] + + 572. [bug] Quoted strings were not accepted as key names in + address match lists. + + 571. [bug] It was possible to create an rdataset of singleton + type which had more than one rdata. [RT #154] + [RT #279] + + 570. [bug] rbtdb.c allowed zones containing nodes which had + both a CNAME and "other data". [RT #154] + + 569. [func] The DNSSEC AD bit will not be set on queries which + have not requested a DNSSEC response. + + 568. [func] Add sample simple database drivers in contrib/sdb. + + 567. [bug] Setting the zone transfer timeout to zero caused an + assertion failure. [RT #302] + + 566. [func] New public function dns_timer_setidle(). + + 565. [func] Log queries more like BIND 8: query logging is now + done to category "queries", level "info". [RT #169] + + 564. [func] Add sortlist support to lwresd. + + 563. [func] New public functions dns_rdatatype_format() and + dns_rdataclass_format(), for convenient formatting + of rdata type/class mnemonics in log messages. + + 562. [cleanup] Moved lib/dns/*conf.c to bin/named where they belong. + + 561. [func] The 'datasize', 'stacksize', 'coresize' and 'files' + clauses of the options{} statement are now implemented. + + 560. [bug] dns_name_split did not properly the resulting prefix + when a maximal length bitstring label was split which + was preceded by another bitstring label. [RT #429] + + 559. [bug] dns_name_split did not properly create the suffix + when splitting within a maximal length bitstring label. + + 558. [func] New functions, isc_resource_getlimit and + isc_resource_setlimit. + + 557. [func] Symbolic constants for libisc integral types. + + 556. [func] The DNSSEC OK bit in the EDNS extended flags + is now implemented. Responses to queries without + this bit set will not contain any DNSSEC records. + + 555. [bug] A slave server attempting a zone transfer could + crash with an assertion failure on certain + malformed responses from the master. [RT #457] + + 554. [bug] In some cases, not all of the dnssec tools were + properly installed. + + 553. [bug] Incoming zone transfers deferred due to quota + were not started when quota was increased but + only when a transfer in progress finished. [RT #456] + + 552. [bug] We were not correctly detecting the end of all c-style + comments. [RT #455] + + 551. [func] Implemented the 'sortlist' option. + + 550. [func] Support unknown rdata types and classes. + + 549. [bug] "make" did not immediately abort the build when a + subdirectory make failed [RT #450]. + + 548. [func] The lexer now ungets tokens more correctly. + + 547. [placeholder] + + 546. [func] Option 'lame-ttl' is now implemented. + + 545. [func] Name limit and counting options removed from dig; + they didn't work properly, and cannot be correctly + implemented without significant changes. + + 544. [func] Add statistics option, enable statistics-file option, + add RNDC option "dump-statistics" to write out a + query statistics file. + + 543. [doc] The 'port' option is now documented. + + 542. [func] Add support for update forwarding as required for + full compliance with RFC2136. It is turned off + by default and can be enabled using the + 'allow-update-forwarding' option. + + 541. [func] Add bogus server support. + + 540. [func] Add dialup support. + + 539. [func] Support the blackhole option. + + 538. [bug] fix buffer overruns by 1 in lwres_getnameinfo(). + + 537. [placeholder] + + 536. [func] Use transfer-source{-v6} when sending refresh queries. + Transfer-source{-v6} now take a optional port + parameter for setting the UDP source port. The port + parameter is ignored for TCP. + + 535. [func] Use transfer-source{-v6} when forwarding update + requests. + + 534. [func] Ancestors have been removed from RBT chains. Ancestor + information can be discerned via node parent pointers. + + 533. [func] Incorporated name hashing into the RBT database to + improve search speed. + + 532. [func] Implement DNS UPDATE pseudo records using + DNS_RDATA_UPDATE flag. + + 531. [func] Rdata really should be initialized before being assigned + to (dns_rdata_fromwire(), dns_rdata_fromtext(), + dns_rdata_clone(), dns_rdata_fromregion()), + check that it is. + + 530. [func] New function dns_rdata_invalidate(). + + 529. [bug] 521 contained a bug which caused zones to always + reload. [RT #410] + + 528. [func] The ISC_LIST_XXXX macros now perform sanity checks + on their arguments. ISC_LIST_XXXXUNSAFE can be use + to skip the checks however use with caution. + + 527. [func] New function dns_rdata_clone(). + + 526. [bug] nsupdate incorrectly refused to add RRs with a TTL + of 0. + + 525. [func] New arguments 'options' for dns_db_subtractrdataset(), + and 'flags' for dns_rdataslab_subtract() allowing you + to request that the RR's must exist prior to deletion. + DNS_R_NOTEXACT is returned if the condition is not met. + + 524. [func] The 'forward' and 'forwarders' statement in + non-forward zones should work now. + + 523. [doc] The source to the Administrator Reference Manual is + now an XML file using the DocBook DTD, and is included + in the distribution. The plain text version of the + ARM is temporarily unavailable while we figure out + how to generate readable plain text from the XML. + + 522. [func] The lightweight resolver daemon can now use + a real configuration file, and its functionality + can be provided by a name server. Also, the -p and -P + options to lwresd have been reversed. + + 521. [bug] Detect master files which contain $INCLUDE and always + reload. [RT #196] + + 520. [bug] Upgraded libtool to 1.3.5, which makes shared + library builds almost work on AIX (and possibly + others). + + 519. [bug] dns_name_split() would improperly split some bitstring + labels, zeroing a few of the least significant bits in + the prefix part. When such an improperly created + prefix was returned to the RBT database, the bogus + label was dutifully stored, corrupting the tree. + [RT #369] + + 518. [bug] The resolver did not realize that a DNAME which was + "the answer" to the client's query was "the answer", + and such queries would fail. [RT #399] + + 517. [bug] The resolver's DNAME code would trigger an assertion + if there was more than one DNAME in the chain. + [RT #399] + + 516. [bug] Cache lookups which had a NULL node pointer, e.g. + those by dns_view_find(), and which would match a + DNAME, would trigger an INSIST(!search.need_cleanup) + assertion. [RT #399] + + 515. [bug] The ssu table was not being attached / detached + by dns_zone_[sg]etssutable. [RT#397] + + 514. [func] Retry refresh and notify queries if they timeout. + [RT #388] + + 513. [func] New functionality added to rdnc and server to allow + individual zones to be refreshed or reloaded. + + 512. [bug] The zone transfer code could throw an exception with + an invalid IXFR stream. + + 511. [bug] The message code could throw an assertion on an + out of memory failure. [RT #392] + + 510. [bug] Remove spurious view notify warning. [RT #376] + + 509. [func] Add support for write of zone files on shutdown. + + 508. [func] dns_message_parse() can now do a best-effort + attempt, which should allow dig to print more invalid + messages. + + 507. [func] New functions dns_zone_flush(), dns_zt_flushanddetach() + and dns_view_flushanddetach(). + + 506. [func] Do not fail to start on errors in zone files. + + 505. [bug] nsupdate was printing "unknown result code". [RT #373] + + 504. [bug] The zone was not being marked as dirty when updated via + IXFR. + + 503. [bug] dumptime was not being set along with + DNS_ZONEFLG_NEEDDUMP. + + 502. [func] On a SERVFAIL reply, DiG will now try the next server + in the list, unless the +fail option is specified. + + 501. [bug] Incorrect port numbers were being displayed by + nslookup. [RT #352] + + 500. [func] Nearly useless +details option removed from DiG. + + 499. [func] In DiG, specifying a class with -c or type with -t + changes command-line parsing so that classes and + types are only recognized if following -c or -t. + This allows hosts with the same name as a class or + type to be looked up. + + 498. [doc] There is now a man page for "dig" + in doc/man/bin/dig.1. + + 497. [bug] The error messages printed when an IP match list + contained a network address with a nonzero host + part where not sufficiently detailed. [RT #365] + + 496. [bug] named didn't sanity check numeric parameters. [RT #361] + + 495. [bug] nsupdate was unable to handle large records. [RT #368] + + 494. [func] Do not cache NXDOMAIN responses for SOA queries. + + 493. [func] Return non-cachable (ttl = 0) NXDOMAIN responses + for SOA queries. This makes it easier to locate + the containing zone without polluting intermediate + caches. + + 492. [bug] attempting to reload a zone caused the server fail + to shutdown cleanly. [RT #360] + + 491. [bug] nsupdate would segfault when sending certain + prerequisites with empty RDATA. [RT #356] + + 490. [func] When a slave/stub zone has not yet successfully + obtained an SOA containing the zone's configured + retry time, perform the SOA query retries using + exponential backoff. [RT #337] + + 489. [func] The zone manager now has a "i/o" queue. + + 488. [bug] Locks weren't properly destroyed in some cases. + + 487. [port] flockfile() is not defined on all systems. + + 486. [bug] nslookup: "set all" and "server" commands showed + the incorrect port number if a port other than 53 + was specified. [RT #352] + + 485. [func] When dig had more than one server to query, it would + send all of the messages at the same time. Add + rate limiting of the transmitted messages. + + 484. [bug] When the server was reloaded after removing addresses + from the named.conf "listen-on" statement, sockets + were still listening on the removed addresses due + to reference count loops. [RT #325] + + 483. [bug] nslookup: "set all" showed a "search" option but it + was not settable. + + 482. [bug] nslookup: a plain "server" or "lserver" should be + treated as a lookup. + + 481. [bug] nslookup:get_next_command() stack size could exceed + per thread limit. + + 480. [bug] strtok() is not thread safe. [RT #349] + + 479. [func] The test suite can now be run by typing "make check" + or "make test" at the top level. + + 478. [bug] "make install" failed if the directory specified with + --prefix did not already exist. + + 477. [bug] The the isc-config.sh script could be installed before + its directory was created. [RT #324] + + 476. [bug] A zone could expire while a zone transfer was in + progress triggering a INSIST failure. [RT #329] + + 475. [bug] query_getzonedb() sometimes returned a non-null version + on failure. This caused assertion failures when + generating query responses where names subject to + additional section processing pointed to a zone + to which access had been denied by means of the + allow-query option. [RT #336] + + 474. [bug] The mnemonic of the CHAOS class is CH according to + RFC1035, but it was printed and read only as CHAOS. + We now accept both forms as input, and print it + as CH. [RT #305] + + 473. [bug] nsupdate overran the end of the list of name servers + when no servers could be reached, typically causing + it to print the error message "dns_request_create: + not implemented". + + 472. [bug] Off-by-one error caused isc_time_add() to sometimes + produce invalid time values. + + 471. [bug] nsupdate didn't compile on HP/UX 10.20 + + 470. [func] $GENERATE is now supported. See also + doc/misc/migration. + + 469. [bug] "query-source address * port 53;" now works. + + 468. [bug] dns_master_load*() failed to report file and line + number in certain error conditions. + + 467. [bug] dns_master_load*() failed to log an error if + pushfile() failed. + + 466. [bug] dns_master_load*() could return success when it failed. + + 465. [cleanup] Allow 0 to be set as an omapi_value_t value by + omapi_value_storeint(). + + 464. [cleanup] Build with openssl's RSA code instead of dnssafe. + + 463. [bug] nsupdate sent malformed SOA queries to the second + and subsequent name servers in resolv.conf if the + query sent to the first one failed. + + 462. [bug] --disable-ipv6 should work now. + + 461. [bug] Specifying an unknown key in the "keys" clause of the + "controls" statement caused a NULL pointer dereference. + [RT #316] + + 460. [bug] Much of the DNSSEC code only worked with class IN. + + 459. [bug] Nslookup processed the "set" command incorrectly. + + 458. [bug] Nslookup didn't properly check class and type values. + [RT #305] + + 457. [bug] Dig/host/hslookup didn't properly handle connect + timeouts in certain situations, causing an + unnecessary warning message to be printed. + + 456. [bug] Stub zones were not resetting the refresh and expire + counters, loadtime or clearing the DNS_ZONE_REFRESH + (refresh in progress) flag upon successful update. + This disabled further refreshing of the stub zone, + causing it to eventually expire. [RT #300] + + 455. [doc] Document IPv4 prefix notation does not require a + dotted decimal quad but may be just dotted decimal. + + 454. [bug] Enforce dotted decimal and dotted decimal quad where + documented as such in named.conf. [RT #304, RT #311] + + 453. [bug] Warn if the obsolete option "maintain-ixfr-base" + is specified in named.conf. [RT #306] + + 452. [bug] Warn if the unimplemented option "statistics-file" + is specified in named.conf. [RT #301] + + 451. [func] Update forwarding implemented. + + 450. [func] New function ns_client_sendraw(). + + 449. [bug] isc_bitstring_copy() only works correctly if the + two bitstrings have the same lsb0 value, but this + requirement was not documented, nor was there a + REQUIRE for it. + + 448. [bug] Host output formatting change, to match v8. [RT #255] + + 447. [bug] Dig didn't properly retry in TCP mode after + a truncated reply. [RT #277] + + 446. [bug] Confusing notify log message. [RT #298] + + 445. [bug] Doing a 0 bit isc_bitstring_copy() of an lsb0 + bitstring triggered a REQUIRE statement. The REQUIRE + statement was incorrect. [RT #297] + + 444. [func] "recursion denied" messages are always logged at + debug level 1, now, rather than sometimes at ERROR. + This silences these warnings in the usual case, where + some clients set the RD bit in all queries. + + 443. [bug] When loading a master file failed because of an + unrecognized RR type name, the error message + did not include the file name and line number. + [RT #285] + + 442. [bug] TSIG signed messages that did not match any view + crashed the server. [RT #290] + + 441. [bug] Nodes obscured by a DNAME were inaccessible even + when DNS_DBFIND_GLUEOK was set. + + 440. [func] New function dns_zone_forwardupdate(). + + 439. [func] New function dns_request_createraw(). + + 438. [func] New function dns_message_getrawmessage(). + + 437. [func] Log NOTIFY activity to the notify channel. + + 436. [bug] If recvmsg() returned EHOSTUNREACH or ENETUNREACH, + which sometimes happens on Linux, named would enter + a busy loop. Also, unexpected socket errors were + not logged at a high enough logging level to be + useful in diagnosing this situation. [RT #275] + + 435. [bug] dns_zone_dump() overwrote existing zone files + rather than writing to a temporary file and + renaming. This could lead to empty or partial + zone files being left around in certain error + conditions involving the initial transfer of a + slave zone, interfering with subsequent server + startup. [RT #282] + + 434. [func] New function isc_file_isabsolute(). + + 433. [func] isc_base64_decodestring() now accepts newlines + within the base64 data. This makes it possible + to break up the key data in a "trusted-keys" + statement into multiple lines. [RT #284] + + 432. [func] Added refresh/retry jitter. The actual refresh/ + retry time is now a random value between 75% and + 100% of the configured value. + + 431. [func] Log at ISC_LOG_INFO when a zone is successfully + loaded. + + 430. [bug] Rewrote the lightweight resolver client management + code to handle shutdown correctly and general + cleanup. + + 429. [bug] The space reserved for a TSIG record in a response + was 2 bytes too short, leading to message + generation failures. + + 428. [bug] rbtdb.c:find_closest_nxt() erroneously returned + DNS_R_BADDB for nodes which had neither NXT nor SIG NXT + (e.g. glue). This could cause SERVFAILs when + generating negative responses in a secure zone. + + 427. [bug] Avoid going into an infinite loop when the validator + gets a negative response to a key query where the + records are signed by the missing key. + + 426. [bug] Attempting to generate an oversized RSA key could + cause dnssec-keygen to dump core. + + 425. [bug] Warn about the auth-nxdomain default value change + if there is no auth-nxdomain statement in the + config file. [RT #287] + + 424. [bug] notify_createmessage() could trigger an assertion + failure when creating the notify message failed, + e.g. due to corrupt zones with multiple SOA records. + [RT #279] + + 423. [bug] When responding to a recursive query, errors that occur + after following a CNAME should cause the query to fail. + [RT #274] + + 422. [func] get rid of isc_random_t, and make isc_random_get() + and isc_random_jitter() use rand() internally + instead of local state. Note that isc_random_*() + functions are only for weak, non-critical "randomness" + such as timing jitter and such. + + 421. [bug] nslookup would exit when given a blank line as input. + + 420. [bug] nslookup failed to implement the "exit" command. + + 419. [bug] The certificate type PKIX was misspelled as SKIX. + + 418. [bug] At debug levels >= 10, getting an unexpected + socket receive error would crash the server + while trying to log the error message. + + 417. [func] Add isc_app_block() and isc_app_unblock(), which + allow an application to handle signals while + blocking. + + 416. [bug] Slave zones with no master file tried to use a + NULL pointer for a journal file name when they + received an IXFR. [RT #273] + + 415. [bug] The logging code leaked file descriptors. + + 414. [bug] Server did not shut down until all incoming zone + transfers were finished. + + 413. [bug] Notify could attempt to use the zone database after + it had been unloaded. [RT#267] + + 412. [bug] named -v didn't print the version. + + 411. [bug] A typo in the HS A code caused an assertion failure. + + 410. [bug] lwres_gethostbyname() and company set lwres_h_errno + to a random value on success. + + 409. [bug] If named was shut down early in the startup + process, ns_omapi_shutdown() would attempt to lock + an uninitialized mutex. [RT #262] + + 408. [bug] stub zones could leak memory and reference counts if + all the masters were unreachable. + + 407. [bug] isc_rwlock_lock() would needlessly block + readers when it reached the read quota even + if no writers were waiting. + + 406. [bug] Log messages were occasionally lost or corrupted + due to a race condition in isc_log_doit(). + + 405. [func] Add support for selective forwarding (forward zones) + + 404. [bug] The request library didn't completely work with IPv6. + + 403. [bug] "host" did not use the search list. + + 402. [bug] Treat undefined acls as errors, rather than + warning and then later throwing an assertion. + [RT #252] + + 401. [func] Added simple database API. + + 400. [bug] SIG(0) signing and verifying was done incorrectly. + [RT #249] + + 399. [bug] When reloading the server with a config file + containing a syntax error, it could catch an + assertion failure trying to perform zone + maintenance on, or sending notifies from, + tentatively created zones whose views were + never fully configured and lacked an address + database and request manager. + + 398. [bug] "dig" sometimes caught an assertion failure when + using TSIG, depending on the key length. + + 397. [func] Added utility functions dns_view_gettsig() and + dns_view_getpeertsig(). + + 396. [doc] There is now a man page for "nsupdate" + in doc/man/bin/nsupdate.8. + + 395. [bug] nslookup printed incorrect RR type mnemonics + for RRs of type >= 21 [RT #237]. + + 394. [bug] Current name was not propagated via $INCLUDE. + + 393. [func] Initial answer while loading (awl) support. + Entry points: dns_master_loadfileinc(), + dns_master_loadstreaminc(), dns_master_loadbufferinc(). + Note: calls to dns_master_load*inc() should be rate + be rate limited so as to not use up all file + descriptors. + + 392. [func] Add ISC_R_FAMILYNOSUPPORT. Returned when OS does + not support the given address family requested. + + 391. [clarity] ISC_R_FAMILY -> ISC_R_FAMILYMISMATCH. + + 390. [func] The function dns_zone_setdbtype() now takes + an argc/argv style vector of words and sets + both the zone database type and its arguments, + making the functions dns_zone_adddbarg() + and dns_zone_cleardbargs() unnecessary. + + 389. [bug] Attempting to send a request over IPv6 using + dns_request_create() on a system without IPv6 + support caused an assertion failure [RT #235]. + + 388. [func] dig and host can now do reverse ipv6 lookups. + + 387. [func] Add dns_byaddr_createptrname(), which converts + an address into the name used by a PTR query. + + 386. [bug] Missing strdup() of ACL name caused random + ACL matching failures [RT #228]. + + 385. [cleanup] Removed functions dns_zone_equal(), dns_zone_print(), + and dns_zt_print(). + + 384. [bug] nsupdate was incorrectly limiting TTLs to 65535 instead + of 2147483647. + + 383. [func] When writing a master file, print the SOA and NS + records (and their SIGs) before other records. + + 382. [bug] named -u failed on many Linux systems where the + libc provided kernel headers do not match + the current kernel. + + 381. [bug] Check for IPV6_RECVPKTINFO and use it instead of + IPV6_PKTINFO if found. [RT #229] + + 380. [bug] nsupdate didn't work with IPv6. + + 379. [func] New library function isc_sockaddr_anyofpf(). + + 378. [func] named and lwresd will log the command line arguments + they were started with in the "starting ..." message. + + 377. [bug] When additional data lookups were refused due to + "allow-query", the databases were still being + attached causing reference leaks. + + 376. [bug] The server should always use good entropy when + performing cryptographic functions needing entropy. + + 375. [bug] Per-zone "allow-query" did not properly override the + view/global one for CNAME targets and additional + data [RT #220]. + + 374. [bug] SOA in authoritative negative responses had wrong TTL. + + 373. [func] nslookup is now installed by "make install". + + 372. [bug] Deal with Microsoft DNS servers appending two bytes of + garbage to zone transfer requests. + + 371. [bug] At high debug levels, doing an outgoing zone transfer + of a very large RRset could cause an assertion failure + during logging. + + 370. [bug] The error messages for roll-forward failures were + overly terse. + + 369. [func] Support new named.conf options, view and zone + statements: + + max-retry-time, min-retry-time, + max-refresh-time, min-refresh-time. + + 368. [func] Restructure the internal ".bind" view so that more + zones can be added to it. + + 367. [bug] Allow proper selection of server on nslookup command + line. + + 366. [func] Allow use of '-' batch file in dig for stdin. + + 365. [bug] nsupdate -k leaked memory. + + 364. [func] Added additional-from-{cache,auth} + + 363. [placeholder] + + 362. [bug] rndc no longer aborts if the configuration file is + missing an options statement. [RT #209] + + 361. [func] When the RBT find or chain functions set the name and + origin for a node that stores the root label + the name is now set to an empty name, instead of ".", + to simplify later use of the name and origin by + dns_name_concatenate(), dns_name_totext() or + dns_name_format(). + + 360. [func] dns_name_totext() and dns_name_format() now allow + an empty name to be passed, which is formatted as "@". + + 359. [bug] dnssec-signzone occasionally signed glue records. + + 358. [cleanup] Rename the intermediate files used by the dnssec + programs. + + 357. [bug] The zone file parser crashed if the argument + to $INCLUDE was a quoted string. + + 356. [cleanup] isc_task_send no longer requires event->sender to + be non-null. + + 355. [func] Added isc_dir_createunique(), similar to mkdtemp(). + + 354. [doc] Man pages for the dnssec tools are now included in + the distribution, in doc/man/dnssec. + + 353. [bug] double increment in lwres/gethost.c:copytobuf(). + [RT# 187] + + 352. [bug] Race condition in dns_client_t startup could cause + an assertion failure. + + 351. [bug] Constructing a response with rcode SERVFAIL to a TSIG + signed query could crash the server. + + 350. [bug] Also-notify lists specified in the global options + block were not correctly reference counted, causing + a memory leak. + + 349. [bug] Processing a query with the CD bit set now works + as expected. + + 348. [func] New boolean named.conf options 'additional-from-auth' + and 'additional-from-cache' now supported in view and + global options statement. + + 347. [bug] Don't crash if an argument is left off options in dig. + + 346. [placeholder] + + 345. [bug] Large-scale changes/cleanups to dig: + * Significantly improve structure handling + * Don't pre-load entire batch files + * Add name/rr counting/limiting + * Fix SIGINT handling + * Shorten timeouts to match v8's behavior + + 344. [bug] When shutting down, lwresd sometimes tried + to shut down its client tasks twice, + triggering an assertion. + + 343. [bug] Although zone maintenance SOA queries and + notify requests were signed with TSIG keys + when configured for the server in case, + the TSIG was not verified on the response. + + 342. [bug] The wrong name was being passed to + dns_name_dup() when generating a TSIG + key using TKEY. + + 341. [func] Support 'key' clause in named.conf zone masters + statement to allow authentication via TSIG keys: + + masters { + 10.0.0.1 port 5353 key "foo"; + 10.0.0.2 ; + }; + + 340. [bug] The top-level COPYRIGHT file was missing from + the distribution. + + 339. [bug] DNSSEC validation of the response to an ANY + query at a name with a CNAME RR in a secure + zone triggered an assertion failure. + + 338. [bug] lwresd logged to syslog as named, not lwresd. + + 337. [bug] "dig" did not recognize "nsap-ptr" as an RR type + on the command line. + + 336. [bug] "dig -f" used 64 k of memory for each line in + the file. It now uses much less, though still + proportionally to the file size. + + 335. [bug] named would occasionally attempt recursion when + it was disallowed or undesired. + + 334. [func] Added hmac-md5 to libisc. + + 333. [bug] The resolver incorrectly accepted referrals to + domains that were not parents of the query name, + causing assertion failures. + + 332. [func] New function dns_name_reset(). + + 331. [bug] Only log "recursion denied" if RD is set. [RT #178] + + 330. [bug] Many debugging messages were partially formatted + even when debugging was turned off, causing a + significant decrease in query performance. + + 329. [func] omapi_auth_register() now takes a size_t argument for + the length of a key's secret data. Previously + OMAPI only stored secrets up to the first NUL byte. + + 328. [func] Added isc_base64_decodestring(). + + 327. [bug] rndc.conf parser wasn't correctly recognizing an IP + address where a host specification was required. + + 326. [func] 'keys' in an 'inet' control statement is now + required and must have at least one item in it. + A "not supported" warning is now issued if a 'unix' + control channel is defined. + + 325. [bug] isc_lex_gettoken was processing octal strings when + ISC_LEXOPT_CNUMBER was not set. + + 324. [func] In the resolver, turn EDNS0 off if there is no + response after a number of retransmissions. + This is to allow queries some chance of succeeding + even if all the authoritative servers of a zone + silently discard EDNS0 requests instead of + sending an error response like they ought to. + + 323. [bug] dns_rbt_findname() did not ignore empty rbt nodes. + Because of this, servers authoritative for a parent + and grandchild zone but not authoritative for the + intervening child zone did not correctly issue + referrals to the servers of the child zone. + + 322. [bug] Queries for KEY RRs are now sent to the parent + server before the authoritative one, making + DNSSEC insecurity proofs work in many cases + where they previously didn't. + + 321. [bug] When synthesizing a CNAME RR for a DNAME + response, query_addcname() failed to initialize + the type and class of the CNAME dns_rdata_t, + causing random failures. + + 320. [func] Multiple rndc changes: parses an rndc.conf file, + uses authentication to talk to named, command + line syntax changed. This will all be described + in the ARM. + + 319. [func] The named.conf "controls" statement is now used + to configure the OMAPI command channel. + + 318. [func] dns_c_ndcctx_destroy() could never return anything + except ISC_R_SUCCESS; made it have void return instead. + + 317. [func] Use callbacks from libomapi to determine if a + new connection is valid, and if a key requested + to be used with that connection is valid. + + 316. [bug] Generate a warning if we detect an unexpected + but treat as . + + 315. [bug] Handle non-empty blanks lines. [RT #163] + + 314. [func] The named.conf controls statement can now have + more than one key specified for the inet clause. + + 313. [bug] When parsing resolv.conf, don't terminate on an + error. Instead, parse as much as possible, but + still return an error if one was found. + + 312. [bug] Increase the number of allowed elements in the + resolv.conf search path from 6 to 8. If there + are more than this, ignore the remainder rather + than returning a failure in lwres_conf_parse. + + 311. [bug] lwres_conf_parse failed when the first line of + resolv.conf was empty or a comment. + + 310. [func] Changes to named.conf "controls" statement (inet + subtype only) + + - support "keys" clause + + controls { + inet * port 1024 + allow { any; } keys { "foo"; } + } + + - allow "port xxx" to be left out of statement, + in which case it defaults to omapi's default port + of 953. + + 309. [bug] When sending a referral, the server did not look + for name server addresses as glue in the zone + holding the NS RRset in the case where this zone + was not the same as the one where it looked for + name server addresses as authoritative data. + + 308. [bug] Treat a SOA record not at top of zone as an error + when loading a zone. [RT #154] + + 307. [bug] When canceling a query, the resolver didn't check for + isc_socket_sendto() calls that did not yet have their + completion events posted, so it could (rarely) end up + destroying the query context and then want to use + it again when the send event posted, triggering an + assertion as it tried to cancel an already-canceled + query. [RT #77] + + 306. [bug] Reading HMAC-MD5 private key files didn't work. + + 305. [bug] When reloading the server with a config file + containing a syntax error, it could catch an + assertion failure trying to perform zone + maintenance on tentatively created zones whose + views were never fully configured and lacked + an address database. + + 304. [bug] If more than LWRES_CONFMAXNAMESERVERS servers + are listed in resolv.conf, silently ignore them + instead of returning failure. + + 303. [bug] Add additional sanity checks to differentiate a AXFR + response vs a IXFR response. [RT #157] + + 302. [bug] In dig, host, and nslookup, MXNAME should be large + enough to hold any legal domain name in presentation + format + terminating NULL. + + 301. [bug] Uninitialized pointer in host:printmessage(). [RT #159] + + 300. [bug] Using both and didn't work + on platforms lacking IPv6 because each included their + own ipv6 header file for the missing definitions. Now + each library's ipv6.h defines the wrapper symbol of + the other (ISC_IPV6_H and LWRES_IPV6_H). + + 299. [cleanup] Get the user and group information before changing the + root directory, so the administrator does not need to + keep a copy of the user and group databases in the + chroot'ed environment. Suggested by Hakan Olsson. + + 298. [bug] A mutex deadlock occurred during shutdown of the + interface manager under certain conditions. + Digital Unix systems were the most affected. + + 297. [bug] Specifying a key name that wasn't fully qualified + in certain parts of the config file could cause + an assertion failure. + + 296. [bug] "make install" from a separate build directory + failed unless configure had been run in the source + directory, too. + + 295. [bug] When invoked with type==CNAME and a message + not constructed by dns_message_parse(), + dns_message_findname() failed to find anything + due to checking for attribute bits that are set + only in dns_message_parse(). This caused an + infinite loop when constructing the response to + an ANY query at a CNAME in a secure zone. + + 294. [bug] If we run out of space in while processing glue + when reading a master file and commit "current name" + reverts to "name_current" instead of staying as + "name_glue". + + 293. [port] Add support for FreeBSD 4.0 system tests. + + 292. [bug] Due to problems with the way some operating systems + handle simultaneous listening on IPv4 and IPv6 + addresses, the server no longer listens on IPv6 + addresses by default. To revert to the previous + behavior, specify "listen-on-v6 { any; };" in + the config file. + + 291. [func] Caching servers no longer send outgoing queries + over TCP just because the incoming recursive query + was a TCP one. + + 290. [cleanup] +twiddle option to dig (for testing only) removed. + + 289. [cleanup] dig is now installed in $bindir instead of $sbindir. + host is now installed in $bindir. (Be sure to remove + any $sbindir/dig from a previous release.) + + 288. [func] rndc is now installed by "make install" into $sbindir. + + 287. [bug] rndc now works again as "rndc 127.1 reload" (for + only that task). Parsing its configuration file and + using digital signatures for authentication has been + disabled until named supports the "controls" statement, + post-9.0.0. + + 286. [bug] On Solaris 2, when named inherited a signal state + where SIGHUP had the SIG_IGN action, SIGHUP would + be ignored rather than causing the server to reload + its configuration. + + 285. [bug] A change made to the dst API for beta4 inadvertently + broke OMAPI's creation of a dst key from an incoming + message, causing an assertion to be triggered. Fixed. + + 284. [func] The DNSSEC key generation and signing tools now + generate randomness from keyboard input on systems + that lack /dev/random. + + 283. [cleanup] The 'lwresd' program is now a link to 'named'. + + 282. [bug] The lexer now returns ISC_R_RANGE if parsed integer is + too big for an unsigned long. + + 281. [bug] Fixed list of recognized config file category names. + + 280. [func] Add isc-config.sh, which can be used to more + easily build applications that link with + our libraries. + + 279. [bug] Private omapi function symbols shared between + two or more files in libomapi.a were not namespace + protected using the ISC convention of starting with + the library name and two underscores ("omapi__"...) + + 278. [bug] bin/named/logconf.c:category_fromconf() didn't take + note of when isc_log_categorybyname() wasn't able + to find the category name and would then apply the + channel list of the unknown category to all categories. + + 277. [bug] isc_log_categorybyname() and isc_log_modulebyname() + would fail to find the first member of any category + or module array apart from the internal defaults. + Thus, for example, the "notify" category was improperly + configured by named. + + 276. [bug] dig now supports maximum sized TCP messages. + + 275. [bug] The definition of lwres_gai_strerror() was missing + the lwres_ prefix. + + 274. [bug] TSIG AXFR verify failed when talking to a BIND 8 + server. + + 273. [func] The default for the 'transfer-format' option is + now 'many-answers'. This will break zone transfers + to BIND 4.9.5 and older unless there is an explicit + 'one-answer' configuration. + + 272. [bug] The sending of large TCP responses was canceled + in mid-transmission due to a race condition + caused by the failure to set the client object's + "newstate" variable correctly when transitioning + to the "working" state. + + 271. [func] Attempt to probe the number of cpus in named + if unspecified rather than defaulting to 1. + + 270. [func] Allow maximum sized TCP answers. + + 269. [bug] Failed DNSSEC validations could cause an assertion + failure by causing clone_results() to be called with + with hevent->node == NULL. + + 268. [doc] A plain text version of the Administrator + Reference Manual is now included in the distribution, + as doc/arm/Bv9ARM.txt. + + 267. [func] Nsupdate is now provided in the distribution. + + 266. [bug] zone.c:save_nsrrset() node was not initialized. + + 265. [bug] dns_request_create() now works for TCP. + + 264. [func] Dispatch can not take TCP sockets in connecting + state. Set DNS_DISPATCHATTR_CONNECTED when calling + dns_dispatch_createtcp() for connected TCP sockets + or call dns_dispatch_starttcp() when the socket is + connected. + + 263. [func] New logging channel type 'stderr' + + channel some-name { + stderr; + severity error; + } + + 262. [bug] 'master' was not initialized in zone.c:stub_callback(). + + 261. [func] Add dns_zone_markdirty(). + + 260. [bug] Running named as a non-root user failed on Linux + kernels new enough to support retaining capabilities + after setuid(). + + 259. [func] New random-device and random-seed-file statements + for global options block of named.conf. Both accept + a single string argument. + + 258. [bug] Fixed printing of lwres_addr_t.address field. + + 257. [bug] The server detached the last zone manager reference + too early, while it could still be in use by queries. + This manifested itself as assertion failures during the + shutdown process for busy name servers. [RT #133] + + 256. [func] isc_ratelimiter_t now has attach/detach semantics, and + isc_ratelimiter_shutdown guarantees that the rate + limiter is detached from its task. + + 255. [func] New function dns_zonemgr_attach(). + + 254. [bug] Suppress "query denied" messages on additional data + lookups. + + --- 9.0.0b4 released --- + + 253. [func] resolv.conf parser now recognizes ';' and '#' as + comments (anywhere in line, not just as the beginning). + + 252. [bug] resolv.conf parser mishandled masks on sortlists. + It also aborted when an unrecognized keyword was seen, + now it silently ignores the entire line. + + 251. [bug] lwresd caught an assertion failure on startup. + + 250. [bug] fixed handling of size+unit when value would be too + large for internal representation. + + 249. [cleanup] max-cache-size config option now takes a size-spec + like 'datasize', except 'default' is not allowed. + + 248. [bug] global lame-ttl option was not being printed when + config structures were written out. + + 247. [cleanup] Rename cache-size config option to max-cache-size. + + 246. [func] Rename global option cachesize to cache-size and + add corresponding option to view statement. + + 245. [bug] If an uncompressed name will take more than 255 + bytes and the buffer is sufficiently long, + dns_name_fromwire should return DNS_R_FORMERR, + not ISC_R_NOSPACE. This bug caused cause the + server to catch an assertion failure when it + received a query for a name longer than 255 + bytes. + + 244. [bug] empty named.conf file and empty options statement are + now parsed properly. + + 243. [func] new cachesize option for named.conf + + 242. [cleanup] fixed incorrect warning about auth-nxdomain usage. + + 241. [cleanup] nscount and soacount have been removed from the + dns_master_*() argument lists. + + 240. [func] databases now come in three flavours: zone, cache + and stub. + + 239. [func] If ISC_MEM_DEBUG is enabled, the variable + isc_mem_debugging controls whether messages + are printed or not. + + 238. [cleanup] A few more compilation warnings have been quieted: + + missing sigwait prototype on BSD/OS 4.0/4.0.1. + + PTHREAD_ONCE_INIT unbraced initializer warnings on + Solaris 2.8. + + IN6ADDR_ANY_INIT unbraced initializer warnings on + BSD/OS 4.*, Linux and Solaris 2.8. + + 237. [bug] If connect() returned ENOBUFS when the resolver was + initiating a TCP query, the socket didn't get + destroyed, and the server did not shut down cleanly. + + 236. [func] Added new listen-on-v6 config file statement. + + 235. [func] Consider it a config file error if a listen-on + statement has an IPv6 address in it, or a + listen-on-v6 statement has an IPv4 address in it. + + 234. [bug] Allow a trusted-key's first field (domain-name) be + either a quoted or an unquoted string, instead of + requiring a quoted string. + + 233. [cleanup] Convert all config structure integer values to unsigned + integer (isc_uint32_t) to match grammar. + + 232. [bug] Allow slave zones to not have a file. + + 231. [func] Support new 'port' clause in config file options + section. Causes 'listen-on', 'masters' and + 'also-notify' statements to use its value instead of + default (53). + + 230. [func] Replace the dst sign/verify API with a cleaner one. + + 229. [func] Support config file sig-validity-interval statement + in options, views and zone statements (master + zones only). + + 228. [cleanup] Logging messages in config module stripped of + trailing period. + + 227. [cleanup] The enumerated identifiers dns_rdataclass_*, + dns_rcode_*, dns_opcode_*, and dns_trust_* are + also now cast to their appropriate types, as with + dns_rdatatype_* in item number 225 below. + + 226. [func] dns_name_totext() now always prints the root name as + '.', even when omit_final_dot is true. + + 225. [cleanup] The enumerated dns_rdatatype_* identifiers are now + cast to dns_rdatatype_t via macros of their same name + so that they are of the proper integral type wherever + a dns_rdatatype_t is needed. + + 224. [cleanup] The entire project builds cleanly with gcc's + -Wcast-qual and -Wwrite-strings warnings enabled, + which is now the default when using gcc. (Warnings + from confparser.c, because of yacc's code, are + unfortunately to be expected.) + + 223. [func] Several functions were re-prototyped to qualify one + or more of their arguments with "const". Similarly, + several functions that return pointers now have + those pointers qualified with const. + + 222. [bug] The global 'also-notify' option was ignored. + + 221. [bug] An uninitialized variable was sometimes passed to + dns_rdata_freestruct() when loading a zone, causing + an assertion failure. + + 220. [cleanup] Set the default outgoing port in the view, and + set it in sockaddrs returned from the ADB. + [31-May-2000 explorer] + + 219. [bug] Signed truncated messages more correctly follow + the respective specs. + + 218. [func] When an rdataset is signed, its ttl is normalized + based on the signature validity period. + + 217. [func] Also-notify and trusted-keys can now be used in + the 'view' statement. + + 216. [func] The 'max-cache-ttl' and 'max-ncache-ttl' options + now work. + + 215. [bug] Failures at certain points in request processing + could cause the assertion INSIST(client->lockview + == NULL) to be triggered. + + 214. [func] New public function isc_netaddr_format(), for + formatting network addresses in log messages. + + 213. [bug] Don't leak memory when reloading the zone if + an update-policy clause was present in the old zone. + + 212. [func] Added dns_message_get/settsigkey, to make TSIG + key management reasonable. + + 211. [func] The 'key' and 'server' statements can now occur + inside 'view' statements. + + 210. [bug] The 'allow-transfer' option was ignored for slave + zones, and the 'transfers-per-ns' option was + was ignored for all zones. + + 209. [cleanup] Upgraded openssl files to new version 0.9.5a + + 208. [func] Added ISC_OFFSET_MAXIMUM for the maximum value + of an isc_offset_t. + + 207. [func] The dnssec tools properly use the logging subsystem. + + 206. [cleanup] dst now stores the key name as a dns_name_t, not + a char *. + + 205. [cleanup] On IRIX, turn off the mostly harmless warnings 1692 + ("prototyped function redeclared without prototype") + and 1552 ("variable ... set but not used") when + compiling in the lib/dns/sec/{dnssafe,openssl} + directories, which contain code imported from outside + sources. + + 204. [cleanup] On HP/UX, pass +vnocompatwarnings to the linker + to quiet the warnings that "The linked output may not + run on a PA 1.x system." + + 203. [func] notify and zone soa queries are now tsig signed when + appropriate. + + 202. [func] isc_lex_getsourceline() changed from returning int + to returning unsigned long, the type of its underlying + counter. + + 201. [cleanup] Removed the test/sdig program, it has been + replaced by bin/dig/dig. + + --- 9.0.0b3 released --- + + 200. [bug] Failures in sending query responses to clients + (e.g., running out of network buffers) were + not logged. + + 199. [bug] isc_heap_delete() sometimes violated the heap + invariant, causing timer events not to be posted + when due. + + 198. [func] Dispatch managers hold memory pools which + any managed dispatcher may use. This allows + us to avoid dipping into the memory context for + most allocations. [19-May-2000 explorer] + + 197. [bug] When an incoming AXFR or IXFR completes, the + zone's internal state is refreshed from the + SOA data. [19-May-2000 explorer] + + 196. [func] Dispatchers can be shared easily between views + and/or interfaces. [19-May-2000 explorer] + + 195. [bug] Including the NXT record of the root domain + in a negative response caused an assertion + failure. + + 194. [doc] The PDF version of the Administrator's Reference + Manual is no longer included in the ISC BIND9 + distribution. + + 193. [func] changed dst_key_free() prototype. + + 192. [bug] Zone configuration validation is now done at end + of config file parsing, and before loading + callbacks. + + 191. [func] Patched to compile on UnixWare 7.x. This platform + is not directly supported by the ISC. + + 190. [cleanup] The DNSSEC tools have been moved to a separate + directory dnssec/ and given the following new, + more descriptive names: + + dnssec-keygen + dnssec-signzone + dnssec-signkey + dnssec-makekeyset + + Their command line arguments have also been changed to + be more consistent. dnssec-keygen now prints the + name of the generated key files (sans extension) + on standard output to simplify its use in automated + scripts. + + 189. [func] isc_time_secondsastimet(), a new function, will ensure + that the number of seconds in an isc_time_t does not + exceed the range of a time_t, or return ISC_R_RANGE. + Similarly, isc_time_now(), isc_time_nowplusinterval(), + isc_time_add() and isc_time_subtract() now check the + range for overflow/underflow. In the case of + isc_time_subtract, this changed a calling requirement + (ie, something that could generate an assertion) + into merely a condition that returns an error result. + isc_time_add() and isc_time_subtract() were void- + valued before but now return isc_result_t. + + 188. [func] Log a warning message when an incoming zone transfer + contains out-of-zone data. + + 187. [func] isc_ratelimter_enqueue() has an additional argument + 'task'. + + 186. [func] dns_request_getresponse() has an additional argument + 'preserve_order'. + + 185. [bug] Fixed up handling of ISC_MEMCLUSTER_LEGACY. Several + public functions did not have an isc__ prefix, and + referred to functions that had previously been + renamed. + + 184. [cleanup] Variables/functions which began with two leading + underscores were made to conform to the ANSI/ISO + standard, which says that such names are reserved. + + 183. [func] ISC_LOG_PRINTTAG option for log channels. Useful + for logging the program name or other identifier. + + 182. [cleanup] New command-line parameters for dnssec tools + + 181. [func] Added dst_key_buildfilename and dst_key_parsefilename + + 180. [func] New isc_result_t ISC_R_RANGE. Supersedes DNS_R_RANGE. + + 179. [func] options named.conf statement *must* now come + before any zone or view statements. + + 178. [func] Post-load of named.conf check verifies a slave zone + has non-empty list of masters defined. + + 177. [func] New per-zone boolean: + + enable-zone yes | no ; + + intended to let a zone be disabled without having + to comment out the entire zone statement. + + 176. [func] New global and per-view option: + + max-cache-ttl number + + 175. [func] New global and per-view option: + + additional-data internal | minimal | maximal; + + 174. [func] New public function isc_sockaddr_format(), for + formatting socket addresses in log messages. + + 173. [func] Keep a queue of zones waiting for zone transfer + quota so that a new transfer can be dispatched + immediately whenever quota becomes available. + + 172. [bug] $TTL directive was sometimes missing from dumped + master files because totext_ctx_init() failed to + initialize ctx->current_ttl_valid. + + 171. [cleanup] On NetBSD systems, the mit-pthreads or + unproven-pthreads library is now always used + unless --with-ptl2 is explicitly specified on + the configure command line. The + --with-mit-pthreads option is no longer needed + and has been removed. + + 170. [cleanup] Remove inter server consistency checks from zone, + these should return as a separate module in 9.1. + dns_zone_checkservers(), dns_zone_checkparents(), + dns_zone_checkchildren(), dns_zone_checkglue(). + + Remove dns_zone_setadb(), dns_zone_setresolver(), + dns_zone_setrequestmgr() these should now be found + via the view. + + 169. [func] ratelimiter can now process N events per interval. + + 168. [bug] include statements in named.conf caused syntax errors + due to not consuming the semicolon ending the include + statement before switching input streams. + + 167. [bug] Make lack of masters for a slave zone a soft error. + + 166. [bug] Keygen was overwriting existing keys if key_id + conflicted, now it will retry, and non-null keys + with key_id == 0 are not generated anymore. Key + was not able to generate NOAUTHCONF DSA key, + increased RSA key size to 2048 bits. + + 165. [cleanup] Silence "end-of-loop condition not reached" warnings + from Solaris compiler. + + 164. [func] Added functions isc_stdio_open(), isc_stdio_close(), + isc_stdio_seek(), isc_stdio_read(), isc_stdio_write(), + isc_stdio_flush(), isc_stdio_sync(), isc_file_remove() + to encapsulate nonportable usage of errno and sync. + + 163. [func] Added result codes ISC_R_FILENOTFOUND and + ISC_R_FILEEXISTS. + + 162. [bug] Ensure proper range for arguments to ctype.h functions. + + 161. [cleanup] error in yyparse prototype that only HPUX caught. + + 160. [cleanup] getnet*() are not going to be implemented at this + stage. + + 159. [func] Redefinition of config file elements is now an + error (instead of a warning). + + 158. [bug] Log channel and category list copy routines + weren't assigning properly to output parameter. + + 157. [port] Fix missing prototype for getopt(). + + 156. [func] Support new 'database' statement in zone. + + database "quoted-string"; + + 155. [bug] ns_notify_start() was not detaching the found zone. + + 154. [func] The signer now logs libdns warnings to stderr even when + not verbose, and in a nicer format. + + 153. [func] dns_rdata_tostruct() 'mctx' is now optional. If 'mctx' + is NULL then you need to preserve the 'rdata' until + you have finished using the structure as there may be + references to the associated memory. If 'mctx' is + non-NULL it is guaranteed that there are no references + to memory associated with 'rdata'. + + dns_rdata_freestruct() must be called if 'mctx' was + non-NULL and may safely be called if 'mctx' was NULL. + + 152. [bug] keygen dumped core if domain name argument was omitted + from command line. + + 151. [func] Support 'disabled' statement in zone config (causes + zone to be parsed and then ignored). Currently must + come after the 'type' clause. + + 150. [func] Support optional ports in masters and also-notify + statements: + + masters [ port xxx ] { y.y.y.y [ port zzz ] ; } + + 149. [cleanup] Removed usused argument 'olist' from + dns_c_view_unsetordering(). + + 148. [cleanup] Stop issuing some warnings about some configuration + file statements that were not implemented, but now are. + + 147. [bug] Changed yacc union size to be smaller for yaccs that + put yacc-stack on the real stack. + + 146. [cleanup] More general redundant header file cleanup. Rather + than continuing to itemize every header which changed, + this changelog entry just notes that if a header file + did not need another header file that it was including + in order to provide its advertised functionality, the + inclusion of the other header file was removed. See + util/check-includes for how this was tested. + + 145. [cleanup] Added and ISC_LANG_BEGINDECLS/ + ISC_LANG_ENDDECLS to header files that had function + prototypes, and removed it from those that did not. + + 144. [cleanup] libdns header files too numerous to name were made + to conform to the same style for multiple inclusion + protection. + + 143. [func] Added function dns_rdatatype_isknown(). + + 142. [cleanup] does not need or + . + + 141. [bug] Corrupt requests with multiple questions could + cause an assertion failure. + + 140. [cleanup] does not need or . + + 139. [cleanup] now includes instead of + and . + + 138. [cleanup] isc_strtouq moved from str.[ch] to string.[ch] and + renamed isc_string_touint64. isc_strsep moved from + strsep.c to string.c and renamed isc_string_separate. + + 137. [cleanup] , , + , and + made to conform to the same style for multiple + inclusion protection. + + 136. [cleanup] , , + and Win32's needed + ISC_LANG_BEGINDECLS/ISC_LANG_ENDDECLS. + + 135. [cleanup] Win32's did not need + or , now uses in place + of , and needed ISC_LANG_BEGINDECLS + and ISC_LANG_ENDDECLS. + + 134. [cleanup] does not need . + + 133. [cleanup] needs . + + 132. [cleanup] does not need , but does + need . + + 131. [cleanup] and need + for ISC_R_* codes used in macros. + + 130. [cleanup] does not need or + , and now includes + instead of . + + 129. [bug] The 'default_debug' log channel was not set up when + 'category default' was present in the config file + + 128. [cleanup] had ISC_LANG_BEGINDECLS instead of + ISC_LANG_ENDDECLS at end of header. + + 127. [cleanup] The contracts for the comparision routines + dns_name_fullcompare(), dns_name_compare(), + dns_name_rdatacompare(), and dns_rdata_compare() now + specify that the order value returned is < 0, 0, or > 0 + instead of -1, 0, or 1. + + 126. [cleanup] and need . + + 125. [cleanup] , , , + , , , and + do not need . + + 124. [func] signer now imports parent's zone key signature + and creates null keys/sets zone status bit for + children when necessary + + 123. [cleanup] does not need . + + 122. [cleanup] does not need or + . + + 121. [cleanup] does not need or + . Multiple inclusion protection + symbol fixed from ISC_SYMBOL_H to ISC_SYMTAB_H. + isc_symtab_t moved to . + + 120. [cleanup] does not need , + , , or + . + + 119. [cleanup] structure definitions for generic rdata structures do + not have _generic_ in their names. + + 118. [cleanup] libdns.a is now namespace-clean, on NetBSD, excepting + YACC crust (yyparse, etc) [2000-apr-27 explorer] + + 117. [cleanup] libdns.a changes: + dns_zone_clearnotify() and dns_zone_addnotify() + are replaced by dns_zone_setnotifyalso(). + dns_zone_clearmasters() and dns_zone_addmaster() + are replaced by dns_zone_setmasters(). + + 116. [func] Added for isc_offset_t (aka off_t + on Unix systems). + + 115. [port] Shut up the -Wmissing-declarations warning about + 's __sputaux on BSD/OS pre-4.1. + + 114. [cleanup] does not need or + . + + 113. [func] Utility programs dig and host added. + + 112. [cleanup] does not need . + + 111. [cleanup] does not need or + . + + 110. [cleanup] does not need or + . + + 109. [bug] "make depend" did nothing for + bin/tests/{db,mem,sockaddr,tasks,timers}/. + + 108. [cleanup] DNS_SETBIT/DNS_GETBIT/DNS_CLEARBIT moved from + to and renamed to + DNS_BIT_SET/DNS_BIT_GET/DNS_BIT_CLEAR. + + 107. [func] Add keysigner and keysettool. + + 106. [func] Allow dnssec verifications to ignore the validity + period. Used by several of the dnssec tools. + + 105. [doc] doc/dev/coding.html expanded with other + implicit conventions the developers have used. + + 104. [bug] Made compress_add and compress_find static to + lib/dns/compress.c. + + 103. [func] libisc buffer API changes for : + Added: + isc_buffer_base(b) (pointer) + isc_buffer_current(b) (pointer) + isc_buffer_active(b) (pointer) + isc_buffer_used(b) (pointer) + isc_buffer_length(b) (int) + isc_buffer_usedlength(b) (int) + isc_buffer_consumedlength(b) (int) + isc_buffer_remaininglength(b) (int) + isc_buffer_activelength(b) (int) + isc_buffer_availablelength(b) (int) + Removed: + ISC_BUFFER_USEDCOUNT(b) + ISC_BUFFER_AVAILABLECOUNT(b) + isc_buffer_type(b) + Changed names: + isc_buffer_used(b, r) -> + isc_buffer_usedregion(b, r) + isc_buffer_available(b, r) -> + isc_buffer_available_region(b, r) + isc_buffer_consumed(b, r) -> + isc_buffer_consumedregion(b, r) + isc_buffer_active(b, r) -> + isc_buffer_activeregion(b, r) + isc_buffer_remaining(b, r) -> + isc_buffer_remainingregion(b, r) + + Buffer types were removed, so the ISC_BUFFERTYPE_* + macros are no more, and the type argument to + isc_buffer_init and isc_buffer_allocate were removed. + isc_buffer_putstr is now void (instead of isc_result_t) + and requires that the caller ensure that there + is enough available buffer space for the string. + + 102. [port] Correctly detect inet_aton, inet_pton and inet_ptop + on BSD/OS 4.1. + + 101. [cleanup] Quieted EGCS warnings from lib/isc/print.c. + + 100. [cleanup] does not need or + . isc_random_t moved to . + + 99. [cleanup] Rate limiter now has separate shutdown() and + destroy() functions, and it guarantees that all + queued events are delivered even in the shutdown case. + + 98. [cleanup] does not need or + unless ISC_PLATFORM_NEEDVSNPRINTF is defined. + + 97. [cleanup] does not need or + . + + 96. [cleanup] does not need . + + 95. [cleanup] does not need . + + 94. [cleanup] Some installed header files did not compile as C++. + + 93. [cleanup] does not need . + + 92. [cleanup] does not need , , + or . + + 91. [cleanup] does not need or + . + + 90. [cleanup] Removed unneeded ISC_LANG_BEGINDECLS/ISC_LANG_ENDDECLS + from . + + 89. [cleanup] does not need . + + 88. [cleanup] does not need or + . isc_interface_t and isc_interfaceiter_t + moved to . + + 87. [cleanup] does not need , + or . + + 86. [cleanup] isc_bufferlist_t moved from to + . + + 85. [cleanup] does not need , + , , or + . + + 84. [func] allow-query ACL checks now apply to all data + added to a response. + + 83. [func] If the server is authoritative for both a + delegating zone and its (nonsecure) delegatee, and + a query is made for a KEY RR at the top of the + delegatee, then the server will look for a KEY + in the delegator if it is not found in the delegatee. + + 82. [cleanup] does not need . + + 81. [cleanup] and do not need + . + + 80. [cleanup] does not need or . + + 79. [cleanup] does not need . + + 78. [cleanup] lwres_conftest renamed to lwresconf_test for + consistency with other *_test programs. + + 77. [cleanup] typedef of isc_time_t and isc_interval_t moved from + to . + + 76. [cleanup] Rewrote keygen. + + 75. [func] Don't load a zone if its database file is older + than the last time the zone was loaded. + + 74. [cleanup] Removed mktemplate.o and ufile.o from libisc.a, + subsumed by file.o. + + 73. [func] New "file" API in libisc, including new function + isc_file_getmodtime, isc_mktemplate renamed to + isc_file_mktemplate and isc_ufile renamed to + isc_file_openunique. By no means an exhaustive API, + it is just what's needed for now. + + 72. [func] DNS_RBTFIND_NOPREDECESSOR and DNS_RBTFIND_NOOPTIONS + added for dns_rbt_findnode, the former to disable the + setting of the chain to the predecessor, and the + latter to make clear when no options are set. + + 71. [cleanup] Made explicit the implicit REQUIREs of + isc_time_seconds, isc_time_nanoseconds, and + isc_time_subtract. + + 70. [func] isc_time_set() added. + + 69. [bug] The zone object's master and also-notify lists grew + longer with each server reload. + + 68. [func] Partial support for SIG(0) on incoming messages. + + 67. [performance] Allow use of alternate (compile-time supplied) + OpenSSL libraries/headers. + + 66. [func] Data in authoritative zones should have a trust level + beyond secure. + + 65. [cleanup] Removed obsolete typedef of dns_zone_callbackarg_t + from . + + 64. [func] The RBT, DB, and zone table APIs now allow the + caller find the most-enclosing superdomain of + a name. + + 63. [func] Generate NOTIFY messages. + + 62. [func] Add UDP refresh support. + + 61. [cleanup] Use single quotes consistently in log messages. + + 60. [func] Catch and disallow singleton types on message + parse. + + 59. [bug] Cause net/host unreachable to be a hard error + when sending and receiving. + + 58. [bug] bin/named/query.c could sometimes trigger the + (client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) + == 0 assertion in query_newname(). + + 57. [func] Added dns_nxt_typepresent() + + 56. [bug] SIG records were not properly returned in cached + negative answers. + + 55. [bug] Responses containing multiple names in the authority + section were not negatively cached. + + 54. [bug] If a fetch with sigrdataset==NULL joined one with + sigrdataset!=NULL or vice versa, the resolver + could catch an assertion or lose signature data, + respectively. + + 53. [port] freebsd 4.0: lib/isc/unix/socket.c requires + . + + 52. [bug] rndc: taskmgr and socketmgr were not initialized + to NULL. + + 51. [cleanup] dns/compress.h and dns/zt.h did not need to include + dns/rbt.h; it was needed only by compress.c and zt.c. + + 50. [func] RBT deletion no longer requires a valid chain to work, + and dns_rbt_deletenode was added. + + 49. [func] Each cache now has its own mctx. + + 48. [func] isc_task_create() no longer takes an mctx. + isc_task_mem() has been eliminated. + + 47. [func] A number of modules now use memory context reference + counting. + + 46. [func] Memory contexts are now reference counted. + Added isc_mem_inuse() and isc_mem_preallocate(). + Renamed isc_mem_destroy_check() to + isc_mem_setdestroycheck(). + + 45. [bug] The trusted-key statement incorrectly loaded keys. + + 44. [bug] Don't include authority data if it would force us + to unset the AD bit in the message. + + 43. [bug] DNSSEC verification of cached rdatasets was failing. + + 42. [cleanup] Simplified logging of messages with embedded domain + names by introducing a new convenience function + dns_name_format(). + + 41. [func] Use PR_SET_KEEPCAPS on Linux 2.3.99-pre3 and later + to allow 'named' to run as a non-root user while + retaining the ability to bind() to privileged + ports. + + 40. [func] Introduced new logging category "dnssec" and + logging module "dns/validator". + + 39. [cleanup] Moved the typedefs for isc_region_t, isc_textregion_t, + and isc_lex_t to . + + 38. [bug] TSIG signed incoming zone transfers work now. + + 37. [bug] If the first RR in an incoming zone transfer was + not an SOA, the server died with an assertion failure + instead of just reporting an error. + + 36. [cleanup] Change DNS_R_SUCCESS (and others) to ISC_R_SUCCESS + + 35. [performance] Log messages which are of a level too high to be + logged by any channel in the logging configuration + will not cause the log mutex to be locked. + + 34. [bug] Recursion was allowed even with 'recursion no'. + + 33. [func] The RBT now maintains a parent pointer at each node. + + 32. [cleanup] bin/lwresd/client.c needs for memset() + prototype. + + 31. [bug] Use ${LIBTOOL} to compile bin/named/main.@O@. + + 30. [func] config file grammar change to support optional + class type for a view. + + 29. [func] support new config file view options: + + auth-nxdomain recursion query-source + query-source-v6 transfer-source + transfer-source-v6 max-transfer-time-out + max-transfer-idle-out transfer-format + request-ixfr provide-ixfr cleaning-interval + fetch-glue notify rfc2308-type1 lame-ttl + max-ncache-ttl min-roots + + 28. [func] support lame-ttl, min-roots and serial-queries + config global options. + + 27. [bug] Only include on BSD/OS 4.[01]*. + Including it on other platforms (eg, NetBSD) can + cause a forced #error from the C preprocessor. + + 26. [func] new match-clients statement in config file view. + + 25. [bug] make install failed to install and + . + + 24. [cleanup] Eliminate some unnecessary #includes of header + files from header files. + + 23. [cleanup] Provide more context in log messages about client + requests, using a new function ns_client_log(). + + 22. [bug] SIGs weren't returned in the answer section when + the query resulted in a fetch. + + 21. [port] Look at STD_CINCLUDES after CINCLUDES during + compilation, so additional system include directories + can be searched but header files in the bind9 source + tree with conflicting names take precedence. This + avoids issues with installed versions of dnssafe and + openssl. + + 20. [func] Configuration file post-load validation of zones + failed if there were no zones. + + 19. [bug] dns_zone_notifyreceive() failed to unlock the zone + lock in certain error cases. + + 18. [bug] Use AC_TRY_LINK rather than AC_TRY_COMPILE in + configure.in to check for presence of in6addr_any. + + 17. [func] Do configuration file post-load validation of zones. + + 16. [bug] put quotes around key names on config file + output to avoid possible keyword clashes. + + 15. [func] Add dns_name_dupwithoffsets(). This function is + improves comparison performance for duped names. + + 14. [bug] free_rbtdb() could have 'put' unallocated memory in + an unlikely error path. + + 13. [bug] lib/dns/master.c and lib/dns/xfrin.c didn't ignore + out-of-zone data. + + 12. [bug] Fixed possible uninitialized variable error. + + 11. [bug] axfr_rrstream_first() didn't check the result code of + db_rr_iterator_first(), possibly causing an assertion + to be triggered later. + + 10. [bug] A bug in the code which makes EDNS0 OPT records in + bin/named/client.c and lib/dns/resolver.c could + trigger an assertion. + + 9. [cleanup] replaced bit-setting code in confctx.c and replaced + repeated code with macro calls. + + 8. [bug] Shutdown of incoming zone transfer accessed + freed memory. + + 7. [cleanup] removed 'listen-on' from view statement. + + 6. [bug] quote RR names when generating config file to + prevent possible clash with config file keywords + (such as 'key'). + + 5. [func] syntax change to named.conf file: new ssu grant/deny + statements must now be enclosed by an 'update-policy' + block. + + 4. [port] bin/named/unix/os.c didn't compile on systems with + linux 2.3 kernel includes due to conflicts between + C library includes and the kernel includes. We now + get only what we need from , and + avoid pulling in other linux kernel .h files. + + 3. [bug] TKEYs go in the answer section of responses, not + the additional section. + + 2. [bug] Generating cryptographic randomness failed on + systems without /dev/random. + + 1. [bug] The installdirs rule in + lib/isc/unix/include/isc/Makefile.in had a typo which + prevented the isc directory from being created if it + didn't exist. + + --- 9.0.0b2 released --- + +# This tells Emacs to use hard tabs in this file. +# Local Variables: +# indent-tabs-mode: t +# End: diff --git a/contrib/bind-9.5.2/COPYRIGHT b/contrib/bind-9.5.2/COPYRIGHT new file mode 100644 index 0000000000..fe042aafc8 --- /dev/null +++ b/contrib/bind-9.5.2/COPYRIGHT @@ -0,0 +1,30 @@ +Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") +Copyright (C) 1996-2003 Internet Software Consortium. + +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: COPYRIGHT,v 1.13.130.2 2009/01/05 23:46:51 tbox Exp $ + +Portions Copyright (C) 1996-2001 Nominum, Inc. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM 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. diff --git a/contrib/bind-9.5.2/FAQ b/contrib/bind-9.5.2/FAQ new file mode 100644 index 0000000000..4df1d764ce --- /dev/null +++ b/contrib/bind-9.5.2/FAQ @@ -0,0 +1,877 @@ +Frequently Asked Questions about BIND 9 + +Copyright © 2004-2009 Internet Systems Consortium, Inc. ("ISC") + +Copyright © 2000-2003 Internet Software Consortium. + +----------------------------------------------------------------------- + +1. Compilation and Installation Questions + +Q: I'm trying to compile BIND 9, and "make" is failing due to files not + being found. Why? + +A: Using a parallel or distributed "make" to build BIND 9 is not + supported, and doesn't work. If you are using one of these, use normal + make or gmake instead. + +Q: Isn't "make install" supposed to generate a default named.conf? + +A: Short Answer: No. + + Long Answer: There really isn't a default configuration which fits any + site perfectly. There are lots of decisions that need to be made and + there is no consensus on what the defaults should be. For example + FreeBSD uses /etc/namedb as the location where the configuration files + for named are stored. Others use /var/named. + + What addresses to listen on? For a laptop on the move a lot you may + only want to listen on the loop back interfaces. + + Who do you offer recursive service to? Is there are firewall to + consider? If so is it stateless or stateful. Are you directly on the + Internet? Are you on a private network? Are you on a NAT'd network? The + answers to all these questions change how you configure even a caching + name server. + +2. Configuration and Setup Questions + +Q: Why does named log the warning message "no TTL specified - using SOA + MINTTL instead"? + +A: Your zone file is illegal according to RFC1035. It must either have a + line like: + + $TTL 86400 + + at the beginning, or the first record in it must have a TTL field, like + the "84600" in this example: + + example.com. 86400 IN SOA ns hostmaster ( 1 3600 1800 1814400 3600 ) + +Q: Why do I get errors like "dns_zone_load: zone foo/IN: loading master + file bar: ran out of space"? + +A: This is often caused by TXT records with missing close quotes. Check + that all TXT records containing quoted strings have both open and close + quotes. + +Q: How do I restrict people from looking up the server version? + +A: Put a "version" option containing something other than the real version + in the "options" section of named.conf. Note doing this will not + prevent attacks and may impede people trying to diagnose problems with + your server. Also it is possible to "fingerprint" nameservers to + determine their version. + +Q: How do I restrict only remote users from looking up the server version? + +A: The following view statement will intercept lookups as the internal + view that holds the version information will be matched last. The + caveats of the previous answer still apply, of course. + + view "chaos" chaos { + match-clients { ; }; + allow-query { none; }; + zone "." { + type hint; + file "/dev/null"; // or any empty file + }; + }; + +Q: What do "no source of entropy found" or "could not open entropy source + foo" mean? + +A: The server requires a source of entropy to perform certain operations, + mostly DNSSEC related. These messages indicate that you have no source + of entropy. On systems with /dev/random or an equivalent, it is used by + default. A source of entropy can also be defined using the + random-device option in named.conf. + +Q: I'm trying to use TSIG to authenticate dynamic updates or zone + transfers. I'm sure I have the keys set up correctly, but the server is + rejecting the TSIG. Why? + +A: This may be a clock skew problem. Check that the the clocks on the + client and server are properly synchronised (e.g., using ntp). + +Q: I see a log message like the following. Why? + + couldn't open pid file '/var/run/named.pid': Permission denied + +A: You are most likely running named as a non-root user, and that user + does not have permission to write in /var/run. The common ways of + fixing this are to create a /var/run/named directory owned by the named + user and set pid-file to "/var/run/named/named.pid", or set pid-file to + "named.pid", which will put the file in the directory specified by the + directory option (which, in this case, must be writable by the named + user). + +Q: I can query the nameserver from the nameserver but not from other + machines. Why? + +A: This is usually the result of the firewall configuration stopping the + queries and / or the replies. + +Q: How can I make a server a slave for both an internal and an external + view at the same time? When I tried, both views on the slave were + transferred from the same view on the master. + +A: You will need to give the master and slave multiple IP addresses and + use those to make sure you reach the correct view on the other machine. + + Master: 10.0.1.1 (internal), 10.0.1.2 (external, IP alias) + internal: + match-clients { !10.0.1.2; !10.0.1.4; 10.0.1/24; }; + notify-source 10.0.1.1; + transfer-source 10.0.1.1; + query-source address 10.0.1.1; + external: + match-clients { any; }; + recursion no; // don't offer recursion to the world + notify-source 10.0.1.2; + transfer-source 10.0.1.2; + query-source address 10.0.1.2; + + Slave: 10.0.1.3 (internal), 10.0.1.4 (external, IP alias) + internal: + match-clients { !10.0.1.2; !10.0.1.4; 10.0.1/24; }; + notify-source 10.0.1.3; + transfer-source 10.0.1.3; + query-source address 10.0.1.3; + external: + match-clients { any; }; + recursion no; // don't offer recursion to the world + notify-source 10.0.1.4; + transfer-source 10.0.1.4; + query-source address 10.0.1.4; + + You put the external address on the alias so that all the other dns + clients on these boxes see the internal view by default. + +A: BIND 9.3 and later: Use TSIG to select the appropriate view. + + Master 10.0.1.1: + key "external" { + algorithm hmac-md5; + secret "xxxxxxxx"; + }; + view "internal" { + match-clients { !key external; // reject message ment for the + // external view. + 10.0.1/24; }; // accept from these addresses. + ... + }; + view "external" { + match-clients { key external; any; }; + server 10.0.1.2 { keys external; }; // tag messages from the + // external view to the + // other servers for the + // view. + recursion no; + ... + }; + + Slave 10.0.1.2: + key "external" { + algorithm hmac-md5; + secret "xxxxxxxx"; + }; + view "internal" { + match-clients { !key external; 10.0.1/24; }; + ... + }; + view "external" { + match-clients { key external; any; }; + server 10.0.1.1 { keys external; }; + recursion no; + ... + }; + +Q: I get error messages like "multiple RRs of singleton type" and "CNAME + and other data" when transferring a zone. What does this mean? + +A: These indicate a malformed master zone. You can identify the exact + records involved by transferring the zone using dig then running + named-checkzone on it. + + dig axfr example.com @master-server > tmp + named-checkzone example.com tmp + + A CNAME record cannot exist with the same name as another record except + for the DNSSEC records which prove its existence (NSEC). + + RFC 1034, Section 3.6.2: "If a CNAME RR is present at a node, no other + data should be present; this ensures that the data for a canonical name + and its aliases cannot be different. This rule also insures that a + cached CNAME can be used without checking with an authoritative server + for other RR types." + +Q: I get error messages like "named.conf:99: unexpected end of input" + where 99 is the last line of named.conf. + +A: There are unbalanced quotes in named.conf. + +A: Some text editors (notepad and wordpad) fail to put a line title + indication (e.g. CR/LF) on the last line of a text file. This can be + fixed by "adding" a blank line to the end of the file. Named expects to + see EOF immediately after EOL and treats text files where this is not + met as truncated. + +Q: How do I share a dynamic zone between multiple views? + +A: You choose one view to be master and the second a slave and transfer + the zone between views. + + Master 10.0.1.1: + key "external" { + algorithm hmac-md5; + secret "xxxxxxxx"; + }; + + key "mykey" { + algorithm hmac-md5; + secret "yyyyyyyy"; + }; + + view "internal" { + match-clients { !key external; 10.0.1/24; }; + server 10.0.1.1 { + /* Deliver notify messages to external view. */ + keys { external; }; + }; + zone "example.com" { + type master; + file "internal/example.db"; + allow-update { key mykey; }; + notify-also { 10.0.1.1; }; + }; + }; + + view "external" { + match-clients { key external; any; }; + zone "example.com" { + type slave; + file "external/example.db"; + masters { 10.0.1.1; }; + transfer-source { 10.0.1.1; }; + // allow-update-forwarding { any; }; + // allow-notify { ... }; + }; + }; + +Q: I get a error message like "zone wireless.ietf56.ietf.org/IN: loading + master file primaries/wireless.ietf56.ietf.org: no owner". + +A: This error is produced when a line in the master file contains leading + white space (tab/space) but the is no current record owner name to + inherit the name from. Usually this is the result of putting white + space before a comment, forgetting the "@" for the SOA record, or + indenting the master file. + +Q: Why are my logs in GMT (UTC). + +A: You are running chrooted (-t) and have not supplied local timezone + information in the chroot area. + + FreeBSD: /etc/localtime + Solaris: /etc/TIMEZONE and /usr/share/lib/zoneinfo + OSF: /etc/zoneinfo/localtime + + See also tzset(3) and zic(8). + +Q: I get "rndc: connect failed: connection refused" when I try to run + rndc. + +A: This is usually a configuration error. + + First ensure that named is running and no errors are being reported at + startup (/var/log/messages or equivalent). Running "named -g " from a title can help at this point. + + Secondly ensure that named is configured to use rndc either by + "rndc-confgen -a", rndc-confgen or manually. The Administrators + Reference manual has details on how to do this. + + Old versions of rndc-confgen used localhost rather than 127.0.0.1 in / + etc/rndc.conf for the default server. Update /etc/rndc.conf if + necessary so that the default server listed in /etc/rndc.conf matches + the addresses used in named.conf. "localhost" has two address + (127.0.0.1 and ::1). + + If you use "rndc-confgen -a" and named is running with -t or -u ensure + that /etc/rndc.conf has the correct ownership and that a copy is in the + chroot area. You can do this by re-running "rndc-confgen -a" with + appropriate -t and -u arguments. + +Q: I get "transfer of 'example.net/IN' from 192.168.4.12#53: failed while + receiving responses: permission denied" error messages. + +A: These indicate a filesystem permission error preventing named creating + / renaming the temporary file. These will usually also have other + associated error messages like + + "dumping master file: sl/tmp-XXXX5il3sQ: open: permission denied" + + Named needs write permission on the directory containing the file. + Named writes the new cache file to a temporary file then renames it to + the name specified in named.conf to ensure that the contents are always + complete. This is to prevent named loading a partial zone in the event + of power failure or similar interrupting the write of the master file. + + Note file names are relative to the directory specified in options and + any chroot directory ([/][]). + + If named is invoked as "named -t /chroot/DNS" with the following + named.conf then "/chroot/DNS/var/named/sl" needs to be writable by the + user named is running as. + + options { + directory "/var/named"; + }; + + zone "example.net" { + type slave; + file "sl/example.net"; + masters { 192.168.4.12; }; + }; + +Q: I want to forward all DNS queries from my caching nameserver to another + server. But there are some domains which have to be served locally, via + rbldnsd. + + How do I achieve this ? + +A: options { + forward only; + forwarders { ; }; + }; + + zone "sbl-xbl.spamhaus.org" { + type forward; forward only; + forwarders { port 530; }; + }; + + zone "list.dsbl.org" { + type forward; forward only; + forwarders { port 530; }; + }; + + +Q: Can you help me understand how BIND 9 uses memory to store DNS zones? + + Some times it seems to take several times the amount of memory it needs + to store the zone. + +A: When reloading a zone named my have multiple copies of the zone in + memory at one time. The zone it is serving and the one it is loading. + If reloads are ultra fast it can have more still. + + e.g. Ones that are transferring out, the one that it is serving and the + one that is loading. + + BIND 8 destroyed the zone before loading and also killed off outgoing + transfers of the zone. + + The new strategy allows slaves to get copies of the new zone regardless + of how often the master is loaded compared to the transfer time. The + slave might skip some intermediate versions but the transfers will + complete and it will keep reasonably in sync with the master. + + The new strategy also allows the master to recover from syntax and + other errors in the master file as it still has an in-core copy of the + old contents. + +Q: I want to use IPv6 locally but I don't have a external IPv6 connection. + External lookups are slow. + +A: You can use server clauses to stop named making external lookups over + IPv6. + + server fd81:ec6c:bd62::/48 { bogus no; }; // site ULA prefix + server ::/0 { bogus yes; }; + +3. Operations Questions + +Q: How to change the nameservers for a zone? + +A: Step 1: Ensure all nameservers, new and old, are serving the same zone + content. + + Step 2: Work out the maximum TTL of the NS RRset in the parent and + child zones. This is the time it will take caches to be clear of a + particular version of the NS RRset. If you are just removing + nameservers you can skip to Step 6. + + Step 3: Add new nameservers to the NS RRset for the zone and wait until + all the servers for the zone are answering with this new NS RRset. + + Step 4: Inform the parent zone of the new NS RRset then wait for all + the parent servers to be answering with the new NS RRset. + + Step 5: Wait for cache to be clear of the old NS RRset. See Step 2 for + how long. If you are just adding nameservers you are done. + + Step 6: Remove any old nameservers from the zones NS RRset and wait for + all the servers for the zone to be serving the new NS RRset. + + Step 7: Inform the parent zone of the new NS RRset then wait for all + the parent servers to be answering with the new NS RRset. + + Step 8: Wait for cache to be clear of the old NS RRset. See Step 2 for + how long. + + Step 9: Turn off the old nameservers or remove the zone entry from the + configuration of the old nameservers. + + Step 10: Increment the serial number and wait for the change to be + visible in all nameservers for the zone. This ensures that zone + transfers are still working after the old servers are decommissioned. + + Note: the above procedure is designed to be transparent to dns clients. + Decommissioning the old servers too early will result in some clients + not being able to look up answers in the zone. + + Note: while it is possible to run the addition and removal stages + together it is not recommended. + +4. General Questions + +Q: I keep getting log messages like the following. Why? + + Dec 4 23:47:59 client 10.0.0.1#1355: updating zone 'example.com/IN': + update failed: 'RRset exists (value dependent)' prerequisite not + satisfied (NXRRSET) + +A: DNS updates allow the update request to test to see if certain + conditions are met prior to proceeding with the update. The message + above is saying that conditions were not met and the update is not + proceeding. See doc/rfc/rfc2136.txt for more details on prerequisites. + +Q: I keep getting log messages like the following. Why? + + Jun 21 12:00:00.000 client 10.0.0.1#1234: update denied + +A: Someone is trying to update your DNS data using the RFC2136 Dynamic + Update protocol. Windows 2000 machines have a habit of sending dynamic + update requests to DNS servers without being specifically configured to + do so. If the update requests are coming from a Windows 2000 machine, + see + for information about how to turn them off. + +Q: When I do a "dig . ns", many of the A records for the root servers are + missing. Why? + +A: This is normal and harmless. It is a somewhat confusing side effect of + the way BIND 9 does RFC2181 trust ranking and of the efforts BIND 9 + makes to avoid promoting glue into answers. + + When BIND 9 first starts up and primes its cache, it receives the root + server addresses as additional data in an authoritative response from a + root server, and these records are eligible for inclusion as additional + data in responses. Subsequently it receives a subset of the root server + addresses as additional data in a non-authoritative (referral) response + from a root server. This causes the addresses to now be considered + non-authoritative (glue) data, which is not eligible for inclusion in + responses. + + The server does have a complete set of root server addresses cached at + all times, it just may not include all of them as additional data, + depending on whether they were last received as answers or as glue. You + can always look up the addresses with explicit queries like "dig + a.root-servers.net A". + +Q: Why don't my zones reload when I do an "rndc reload" or SIGHUP? + +A: A zone can be updated either by editing zone files and reloading the + server or by dynamic update, but not both. If you have enabled dynamic + update for a zone using the "allow-update" option, you are not supposed + to edit the zone file by hand, and the server will not attempt to + reload it. + +Q: Why is named listening on UDP port other than 53? + +A: Named uses a system selected port to make queries of other nameservers. + This behaviour can be overridden by using query-source to lock down the + port and/or address. See also notify-source and transfer-source. + +Q: I get warning messages like "zone example.com/IN: refresh: failure + trying master 1.2.3.4#53: timed out". + +A: Check that you can make UDP queries from the slave to the master + + dig +norec example.com soa @1.2.3.4 + + You could be generating queries faster than the slave can cope with. + Lower the serial query rate. + + serial-query-rate 5; // default 20 + +Q: I don't get RRSIG's returned when I use "dig +dnssec". + +A: You need to ensure DNSSEC is enabled (dnssec-enable yes;). + +Q: Can a NS record refer to a CNAME. + +A: No. The rules for glue (copies of the *address* records in the parent + zones) and additional section processing do not allow it to work. + + You would have to add both the CNAME and address records (A/AAAA) as + glue to the parent zone and have CNAMEs be followed when doing + additional section processing to make it work. No nameserver + implementation supports either of these requirements. + +Q: What does "RFC 1918 response from Internet for 0.0.0.10.IN-ADDR.ARPA" + mean? + +A: If the IN-ADDR.ARPA name covered refers to a internal address space you + are using then you have failed to follow RFC 1918 usage rules and are + leaking queries to the Internet. You should establish your own zones + for these addresses to prevent you querying the Internet's name servers + for these addresses. Please see for details of the + problems you are causing and the counter measures that have had to be + deployed. + + If you are not using these private addresses then a client has queried + for them. You can just ignore the messages, get the offending client to + stop sending you these messages as they are most probably leaking them + or setup your own zones empty zones to serve answers to these queries. + + zone "10.IN-ADDR.ARPA" { + type master; + file "empty"; + }; + + zone "16.172.IN-ADDR.ARPA" { + type master; + file "empty"; + }; + + ... + + zone "31.172.IN-ADDR.ARPA" { + type master; + file "empty"; + }; + + zone "168.192.IN-ADDR.ARPA" { + type master; + file "empty"; + }; + + empty: + @ 10800 IN SOA . . ( + 1 3600 1200 604800 10800 ) + @ 10800 IN NS . + + Note + + Future versions of named are likely to do this automatically. + +Q: Will named be affected by the 2007 changes to daylight savings rules in + the US. + +A: No, so long as the machines internal clock (as reported by "date -u") + remains at UTC. The only visible change if you fail to upgrade your OS, + if you are in a affected area, will be that log messages will be a hour + out during the period where the old rules do not match the new rules. + + For most OS's this change just means that you need to update the + conversion rules from UTC to local time. Normally this involves + updating a file in /etc (which sets the default timezone for the + machine) and possibly a directory which has all the conversion rules + for the world (e.g. /usr/share/zoneinfo). When updating the OS do not + forget to update any chroot areas as well. See your OS's documentation + for more details. + + The local timezone conversion rules can also be done on a individual + basis by setting the TZ environment variable appropriately. See your + OS's documentation for more details. + +Q: Is there a bugzilla (or other tool) database that mere mortals can have + (read-only) access to for bind? + +A: No. The BIND 9 bug database is kept closed for a number of reasons. + These include, but are not limited to, that the database contains + proprietory information from people reporting bugs. The database has in + the past and may in future contain unfixed bugs which are capable of + bringing down most of the Internet's DNS infrastructure. + + The release pages for each version contain up to date lists of bugs + that have been fixed post release. That is as close as we can get to + providing a bug database. + +Q: Why do queries for NSEC3 records fail to return the NSEC3 record? + +A: NSEC3 records are strictly meta data and can only be returned in the + authority section. This is done so that signing the zone using NSEC3 + records does not bring names into existence that do not exist in the + unsigned version of the zone. + +5. Operating-System Specific Questions + +5.1. HPUX + +Q: I get the following error trying to configure BIND: + + checking if unistd.h or sys/types.h defines fd_set... no + configure: error: need either working unistd.h or sys/select.h + +A: You have attempted to configure BIND with the bundled C compiler. This + compiler does not meet the minimum compiler requirements to for + building BIND. You need to install a ANSI C compiler and / or teach + configure how to find the ANSI C compiler. The later can be done by + adjusting the PATH environment variable and / or specifying the + compiler via CC. + + ./configure CC= ... + +5.2. Linux + +Q: Why do I get the following errors: + + general: errno2result.c:109: unexpected error: + general: unable to convert errno to isc_result: 14: Bad address + client: UDP client handler shutting down due to fatal receive error: unexpected error + +A: This is the result of a Linux kernel bug. + + See: + +Q: Why does named lock up when it attempts to connect over IPSEC tunnels? + +A: This is due to a kernel bug where the fact that a socket is marked + non-blocking is ignored. It is reported that setting xfrm_larval_drop + to 1 helps but this may have negative side effects. See: and . + + xfrm_larval_drop can be set to 1 by the following procedure: + + echo "1" > proc/sys/net/core/xfrm_larval_drop + +Q: Why do I see 5 (or more) copies of named on Linux? + +A: Linux threads each show up as a process under ps. The approximate + number of threads running is n+4, where n is the number of CPUs. Note + that the amount of memory used is not cumulative; if each process is + using 10M of memory, only a total of 10M is used. + + Newer versions of Linux's ps command hide the individual threads and + require -L to display them. + +Q: Why does BIND 9 log "permission denied" errors accessing its + configuration files or zones on my Linux system even though it is + running as root? + +A: On Linux, BIND 9 drops most of its root privileges on startup. This + including the privilege to open files owned by other users. Therefore, + if the server is running as root, the configuration files and zone + files should also be owned by root. + +Q: I get the error message "named: capset failed: Operation not permitted" + when starting named. + +A: The capability module, part of "Linux Security Modules/LSM", has not + been loaded into the kernel. See insmod(8), modprobe(8). + + The relevant modules can be loaded by running: + + modprobe commoncap + modprobe capability + +Q: I'm running BIND on Red Hat Enterprise Linux or Fedora Core - + + Why can't named update slave zone database files? + + Why can't named create DDNS journal files or update the master zones + from journals? + + Why can't named create custom log files? + +A: Red Hat Security Enhanced Linux (SELinux) policy security protections : + + Red Hat have adopted the National Security Agency's SELinux security + policy (see ) and recommendations for BIND + security , which are more secure than running named in a chroot and + make use of the bind-chroot environment unnecessary . + + By default, named is not allowed by the SELinux policy to write, create + or delete any files EXCEPT in these directories: + + $ROOTDIR/var/named/slaves + $ROOTDIR/var/named/data + $ROOTDIR/var/tmp + + + where $ROOTDIR may be set in /etc/sysconfig/named if bind-chroot is + installed. + + The SELinux policy particularly does NOT allow named to modify the + $ROOTDIR/var/named directory, the default location for master zone + database files. + + SELinux policy overrules file access permissions - so even if all the + files under /var/named have ownership named:named and mode rw-rw-r--, + named will still not be able to write or create files except in the + directories above, with SELinux in Enforcing mode. + + So, to allow named to update slave or DDNS zone files, it is best to + locate them in $ROOTDIR/var/named/slaves, with named.conf zone + statements such as: + + zone "slave.zone." IN { + type slave; + file "slaves/slave.zone.db"; + ... + }; + zone "ddns.zone." IN { + type master; + allow-updates {...}; + file "slaves/ddns.zone.db"; + }; + + + To allow named to create its cache dump and statistics files, for + example, you could use named.conf options statements such as: + + options { + ... + dump-file "/var/named/data/cache_dump.db"; + statistics-file "/var/named/data/named_stats.txt"; + ... + }; + + + You can also tell SELinux to allow named to update any zone database + files, by setting the SELinux tunable boolean parameter + 'named_write_master_zones=1', using the system-config-securitylevel + GUI, using the 'setsebool' command, or in /etc/selinux/targeted/ + booleans. + + You can disable SELinux protection for named entirely by setting the + 'named_disable_trans=1' SELinux tunable boolean parameter. + + The SELinux named policy defines these SELinux contexts for named: + + named_zone_t : for zone database files - $ROOTDIR/var/named/* + named_conf_t : for named configuration files - $ROOTDIR/etc/{named,rndc}.* + named_cache_t: for files modifiable by named - $ROOTDIR/var/{tmp,named/{slaves,data}} + + + If you want to retain use of the SELinux policy for named, and put + named files in different locations, you can do so by changing the + context of the custom file locations . + + To create a custom configuration file location, e.g. '/root/ + named.conf', to use with the 'named -c' option, do: + + # chcon system_u:object_r:named_conf_t /root/named.conf + + + To create a custom modifiable named data location, e.g. '/var/log/ + named' for a log file, do: + + # chcon system_u:object_r:named_cache_t /var/log/named + + + To create a custom zone file location, e.g. /root/zones/, do: + + # chcon system_u:object_r:named_zone_t /root/zones/{.,*} + + + See these man-pages for more information : selinux(8), named_selinux + (8), chcon(1), setsebool(8) + +Q: Listening on individual IPv6 interfaces does not work. + +A: This is usually due to "/proc/net/if_inet6" not being available in the + chroot file system. Mount another instance of "proc" in the chroot file + system. + + This can be be made permanent by adding a second instance to /etc/ + fstab. + + proc /proc proc defaults 0 0 + proc /var/named/proc proc defaults 0 0 + +5.3. Windows + +Q: Zone transfers from my BIND 9 master to my Windows 2000 slave fail. + Why? + +A: This may be caused by a bug in the Windows 2000 DNS server where DNS + messages larger than 16K are not handled properly. This can be worked + around by setting the option "transfer-format one-answer;". Also check + whether your zone contains domain names with embedded spaces or other + special characters, like "John\032Doe\213s\032Computer", since such + names have been known to cause Windows 2000 slaves to incorrectly + reject the zone. + +Q: I get "Error 1067" when starting named under Windows. + +A: This is the service manager saying that named exited. You need to + examine the Application log in the EventViewer to find out why. + + Common causes are that you failed to create "named.conf" (usually "C:\ + windows\dns\etc\named.conf") or failed to specify the directory in + named.conf. + + options { + Directory "C:\windows\dns\etc"; + }; + +5.4. FreeBSD + +Q: I have FreeBSD 4.x and "rndc-confgen -a" just sits there. + +A: /dev/random is not configured. Use rndcontrol(8) to tell the kernel to + use certain interrupts as a source of random events. You can make this + permanent by setting rand_irqs in /etc/rc.conf. + + rand_irqs="3 14 15" + + See also . + +5.5. Solaris + +Q: How do I integrate BIND 9 and Solaris SMF + +A: Sun has a blog entry describing how to do this. + + + +5.6. Apple Mac OS X + +Q: How do I run BIND 9 on Apple Mac OS X? + +A: If you run Tiger(Mac OS 10.4) or later then this is all you need to do: + + % sudo rndc-confgen > /etc/rndc.conf + + Copy the key statement from /etc/rndc.conf into /etc/rndc.key, e.g.: + + key "rndc-key" { + algorithm hmac-md5; + secret "uvceheVuqf17ZwIcTydddw=="; + }; + + Then start the relevant service: + + % sudo service org.isc.named start + + This is persistent upon a reboot, so you will have to do it only once. + +A: Alternatively you can just generate /etc/rndc.key by running: + + % sudo rndc-confgen -a + + Then start the relevant service: + + % sudo service org.isc.named start + + Named will look for /etc/rndc.key when it starts if it doesn't have a + controls section or the existing controls are missing keys sub-clauses. + This is persistent upon a reboot, so you will have to do it only once. + diff --git a/contrib/bind-9.5.2/README b/contrib/bind-9.5.2/README new file mode 100644 index 0000000000..8fdec25327 --- /dev/null +++ b/contrib/bind-9.5.2/README @@ -0,0 +1,577 @@ +BIND 9 + + BIND version 9 is a major rewrite of nearly all aspects of the + underlying BIND architecture. Some of the important features of + BIND 9 are: + + - DNS Security + DNSSEC (signed zones) + TSIG (signed DNS requests) + + - IP version 6 + Answers DNS queries on IPv6 sockets + IPv6 resource records (AAAA) + Experimental IPv6 Resolver Library + + - DNS Protocol Enhancements + IXFR, DDNS, Notify, EDNS0 + Improved standards conformance + + - Views + One server process can provide multiple "views" of + the DNS namespace, e.g. an "inside" view to certain + clients, and an "outside" view to others. + + - Multiprocessor Support + + - Improved Portability Architecture + + + BIND version 9 development has been underwritten by the following + organizations: + + Sun Microsystems, Inc. + Hewlett Packard + Compaq Computer Corporation + IBM + Process Software Corporation + Silicon Graphics, Inc. + Network Associates, Inc. + U.S. Defense Information Systems Agency + USENIX Association + Stichting NLnet - NLnet Foundation + Nominum, Inc. + + +BIND 9.5.2 + + BIND 9.5.2 is a maintenance release, fixing bugs in 9.5.1. + +BIND 9.5.1 + + BIND 9.5.1 is a maintenance release, fixing bugs in 9.5.0. + +BIND 9.5.0 + + BIND 9.5.0 has a number of new features over 9.4, + including: + + - GSS-TSIG support (RFC 3645). + - DHCID support. + - Experimental http server and statistics support for named via xml. + - More detailed statistics counters including those supported in + BIND 8. + - Faster ACL processing. + - Internal documentation generated by Doxygen. + - Efficient LRU cache-cleaning mechanism. + - NSID support (RFC 5001). + +BIND 9.4.0 + + BIND 9.4.0 has a number of new features over 9.3, + including: + + Implemented "additional section caching (or acache)", an + internal cache framework for additional section content to + improve response performance. Several configuration options + were provided to control the behavior. + + New notify type 'master-only'. Enable notify for master + zones only. + + Accept 'notify-source' style syntax for query-source. + + rndc now allows addresses to be set in the server clauses. + + New option "allow-query-cache". This lets "allow-query" + be used to specify the default zone access level rather + than having to have every zone override the global value. + "allow-query-cache" can be set at both the options and view + levels. If "allow-query-cache" is not set then "allow-recursion" + is used if set, otherwise "allow-query" is used if set + unless "recursion no;" is set in which case "none;" is used, + otherwise the default (localhost; localnets;) is used. + + rndc: the source address can now be specified. + + ixfr-from-differences now takes master and slave in addition + to yes and no at the options and view levels. + + Allow the journal's name to be changed via named.conf. + + 'rndc notify zone [class [view]]' resend the NOTIFY messages + for the specified zone. + + 'dig +trace' now randomly selects the next servers to try. + Report if there is a bad delegation. + + Improve check-names error messages. + + Make public the function to read a key file, dst_key_read_public(). + + dig now returns the byte count for axfr/ixfr. + + allow-update is now settable at the options / view level. + + named-checkconf now checks the logging configuration. + + host now can turn on memory debugging flags with '-m'. + + Don't send notify messages to self. + + Perform sanity checks on NS records which refer to 'in zone' names. + + New zone option "notify-delay". Specify a minimum delay + between sets of NOTIFY messages. + + Extend adjusting TTL warning messages. + + Named and named-checkzone can now both check for non-terminal + wildcard records. + + "rndc freeze/thaw" now freezes/thaws all zones. + + named-checkconf now check acls to verify that they only + refer to existing acls. + + The server syntax has been extended to support a range of + servers. + + Report differences between hints and real NS rrset and + associated address records. + + Preserve the case of domain names in rdata during zone + transfers. + + Restructured the data locking framework using architecture + dependent atomic operations (when available), improving + response performance on multi-processor machines significantly. + x86, x86_64, alpha, powerpc, and mips are currently supported. + + UNIX domain controls are now supported. + + Add support for additional zone file formats for improving + loading performance. The masterfile-format option in + named.conf can be used to specify a non-default format. A + separate command named-compilezone was provided to generate + zone files in the new format. Additionally, the -I and -O + options for dnssec-signzone specify the input and output + formats. + + dnssec-signzone can now randomize signature end times + (dnssec-signzone -j jitter). + + Add support for CH A record. + + Add additional zone data constancy checks. named-checkzone + has extended checking of NS, MX and SRV record and the hosts + they reference. named has extended post zone load checks. + New zone options: check-mx and integrity-check. + + + edns-udp-size can now be overridden on a per server basis. + + dig can now specify the EDNS version when making a query. + + Added framework for handling multiple EDNS versions. + + Additional memory debugging support to track size and mctx + arguments. + + Detect duplicates of UDP queries we are recursing on and + drop them. New stats category "duplicates". + + "USE INTERNAL MALLOC" is now runtime selectable. + + The lame cache is now done on a basis + as some servers only appear to be lame for certain query + types. + + Limit the number of recursive clients that can be waiting + for a single query () to resolve. New + options clients-per-query and max-clients-per-query. + + dig: report the number of extra bytes still left in the + packet after processing all the records. + + Support for IPSECKEY rdata type. + + Raise the UDP recieve buffer size to 32k if it is less than 32k. + + x86 and x86_64 now have seperate atomic locking implementations. + + named-checkconf now validates update-policy entries. + + Attempt to make the amount of work performed in a iteration + self tuning. The covers nodes clean from the cache per + iteration, nodes written to disk when rewriting a master + file and nodes destroyed per iteration when destroying a + zone or a cache. + + ISC string copy API. + + Automatic empty zone creation for D.F.IP6.ARPA and friends. + Note: RFC 1918 zones are not yet covered by this but are + likely to be in a future release. + + New options: empty-server, empty-contact, empty-zones-enable + and disable-empty-zone. + + dig now has a '-q queryname' and '+showsearch' options. + + host/nslookup now continue (default)/fail on SERVFAIL. + + dig now warns if 'RA' is not set in the answer when 'RD' + was set in the query. host/nslookup skip servers that fail + to set 'RA' when 'RD' is set unless a server is explicitly + set. + + Integrate contibuted DLZ code into named. + + Integrate contibuted IDN code from JPNIC. + + libbind: corresponds to that from BIND 8.4.7. + +BIND 9.3.0 + + BIND 9.3.0 has a number of new features over 9.2, + including: + + DNSSEC is now DS based (RFC 3658). + See also RFC 3845, doc/draft/draft-ietf-dnsext-dnssec-*. + + DNSSEC lookaside validation. + + check-names is now implemented. + rrset-order in more complete. + + IPv4/IPv6 transition support, dual-stack-servers. + + IXFR deltas can now be generated when loading master files, + ixfr-from-differences. + + It is now possible to specify the size of a journal, max-journal-size. + + It is now possible to define a named set of master servers to be + used in masters clause, masters. + + The advertised EDNS UDP size can now be set, edns-udp-size. + + allow-v6-synthesis has been obsoleted. + + NOTE: + * Zones containing MD and MF will now be rejected. + * dig, nslookup name. now report "Not Implemented" as + NOTIMP rather than NOTIMPL. This will have impact on scripts + that are looking for NOTIMPL. + + libbind: corresponds to that from BIND 8.4.5. + +BIND 9.2.0 + + BIND 9.2.0 has a number of new features over 9.1, + including: + + - The size of the cache can now be limited using the + "max-cache-size" option. + + - The server can now automatically convert RFC1886-style + recursive lookup requests into RFC2874-style lookups, + when enabled using the new option "allow-v6-synthesis". + This allows stub resolvers that support AAAA records + but not A6 record chains or binary labels to perform + lookups in domains that make use of these IPv6 DNS + features. + + - Performance has been improved. + + - The man pages now use the more portable "man" macros + rather than the "mandoc" macros, and are installed + by "make install". + + - The named.conf parser has been completely rewritten. + It now supports "include" directives in more + places such as inside "view" statements, and it no + longer has any reserved words. + + - The "rndc status" command is now implemented. + + - rndc can now be configured automatically. + + - A BIND 8 compatible stub resolver library is now + included in lib/bind. + + - OpenSSL has been removed from the distribution. This + means that to use DNSSEC, OpenSSL must be installed and + the --with-openssl option must be supplied to configure. + This does not apply to the use of TSIG, which does not + require OpenSSL. + + - The source distribution now builds on Windows. + See win32utils/readme1.txt and win32utils/win32-build.txt + for details. + + This distribution also includes a new lightweight stub + resolver library and associated resolver daemon that fully + support forward and reverse lookups of both IPv4 and IPv6 + addresses. This library is considered experimental and + is not a complete replacement for the BIND 8 resolver library. + Applications that use the BIND 8 res_* functions to perform + DNS lookups or dynamic updates still need to be linked against + the BIND 8 libraries. For DNS lookups, they can also use the + new "getrrsetbyname()" API. + + BIND 9.2 is capable of acting as an authoritative server + for DNSSEC secured zones. This functionality is believed to + be stable and complete except for lacking support for + verifications involving wildcard records in secure zones. + + When acting as a caching server, BIND 9.2 can be configured + to perform DNSSEC secure resolution on behalf of its clients. + This part of the DNSSEC implementation is still considered + experimental. For detailed information about the state of the + DNSSEC implementation, see the file doc/misc/dnssec. + + There are a few known bugs: + + On some systems, IPv6 and IPv4 sockets interact in + unexpected ways. For details, see doc/misc/ipv6. + To reduce the impact of these problems, the server + no longer listens for requests on IPv6 addresses + by default. If you need to accept DNS queries over + IPv6, you must specify "listen-on-v6 { any; };" + in the named.conf options statement. + + FreeBSD prior to 4.2 (and 4.2 if running as non-root) + and OpenBSD prior to 2.8 log messages like + "fcntl(8, F_SETFL, 4): Inappropriate ioctl for device". + This is due to a bug in "/dev/random" and impacts the + server's DNSSEC support. + + OS X 10.1.4 (Darwin 5.4), OS X 10.1.5 (Darwin 5.5) and + OS X 10.2 (Darwin 6.0) reports errors like + "fcntl(3, F_SETFL, 4): Operation not supported by device". + This is due to a bug in "/dev/random" and impacts the + server's DNSSEC support. + + --with-libtool does not work on AIX. + + A bug in some versions of the Microsoft DNS server can cause zone + transfers from a BIND 9 server to a W2K server to fail. For details, + see the "Zone Transfers" section in doc/misc/migration. + + For a detailed list of user-visible changes from + previous releases, see the CHANGES file. + + +Building + + BIND 9 currently requires a UNIX system with an ANSI C compiler, + basic POSIX support, and a 64 bit integer type. + + We've had successful builds and tests on the following systems: + + COMPAQ Tru64 UNIX 5.1B + Fedora Core 6 + FreeBSD 4.10, 5.2.1, 6.2 + HP-UX 11.11 + Mac OS X 10.5 + NetBSD 3.x and 4.0-beta + OpenBSD 3.3 and up + Solaris 8, 9, 9 (x86), 10 + Ubuntu 7.04, 7.10 + Windows XP/2003/2008 + + NOTE: As of BIND 9.5.1, 9.4.3, and 9.3.6, older versions of + Windows, including Windows NT and Windows 2000, are no longer + supported. + + We have recent reports from the user community that a supported + version of BIND will build and run on the following systems: + + AIX 4.3, 5L + CentOS 4, 4.5, 5 + Darwin 9.0.0d1/ARM + Debian 4 + Fedora Core 5, 7 + FreeBSD 6.1 + HP-UX 11.23 PA + MacOS X 10.4, 10.5 + Red Hat Enterprise Linux 4, 5 + SCO OpenServer 5.0.6 + Slackware 9, 10 + SuSE 9, 10 + + To build, just + + ./configure + make + + Do not use a parallel "make". + + Several environment variables that can be set before running + configure will affect compilation: + + CC + The C compiler to use. configure tries to figure + out the right one for supported systems. + + CFLAGS + C compiler flags. Defaults to include -g and/or -O2 + as supported by the compiler. + + STD_CINCLUDES + System header file directories. Can be used to specify + where add-on thread or IPv6 support is, for example. + Defaults to empty string. + + STD_CDEFINES + Any additional preprocessor symbols you want defined. + Defaults to empty string. + + Possible settings: + Change the default syslog facility of named/lwresd. + -DISC_FACILITY=LOG_LOCAL0 + Enable DNSSEC signature chasing support in dig. + -DDIG_SIGCHASE=1 (sets -DDIG_SIGCHASE_TD=1 and + -DDIG_SIGCHASE_BU=1) + Disable dropping queries from particular well known ports. + -DNS_CLIENT_DROPPORT=0 + Sibling glue checking in named-checkzone is enabled by default. + To disable the default check set. -DCHECK_SIBLING=0 + named-checkzone checks out-of-zone addresses by default. + To disable this default set. -DCHECK_LOCAL=0 + Enable workaround for Solaris kernel bug about /dev/poll + -DISC_SOCKET_USE_POLLWATCH=1 + The watch timeout is also configurable, e.g., + -DISC_SOCKET_POLLWATCH_TIMEOUT=20 + + LDFLAGS + Linker flags. Defaults to empty string. + + The following need to be set when cross compiling. + + BUILD_CC + The native C compiler. + BUILD_CFLAGS (optional) + BUILD_CPPFLAGS (optional) + Possible Settings: + -DNEED_OPTARG=1 (optarg is not declared in ) + BUILD_LDFLAGS (optional) + BUILD_LIBS (optional) + + To build shared libraries, specify "--with-libtool" on the + configure command line. + + For the server to support DNSSEC, you need to build it + with crypto support. You must have OpenSSL 0.9.5a + or newer installed and specify "--with-openssl" on the + configure command line. If OpenSSL is installed under + a nonstandard prefix, you can tell configure where to + look for it using "--with-openssl=/prefix". + + To build libbind (the BIND 8 resolver library), specify + "--enable-libbind" on the configure command line. + + On some platforms it is necessary to explictly request large + file support to handle files bigger than 2GB. This can be + done by "--enable-largefile" on the configure command line. + + On some platforms, BIND 9 can be built with multithreading + support, allowing it to take advantage of multiple CPUs. + You can specify whether to build a multithreaded BIND 9 + by specifying "--enable-threads" or "--disable-threads" + on the configure command line. The default is operating + system dependent. + + Support for the "fixed" rrset-order option can be enabled + or disabled by specifying "--enable-fixed-rrset" or + "--disable-fixed-rrset" on the configure command line. + The default is "disabled", to reduce memory footprint. + + If your operating system has integrated support for IPv6, it + will be used automatically. If you have installed KAME IPv6 + separately, use "--with-kame[=PATH]" to specify its location. + + "make install" will install "named" and the various BIND 9 libraries. + By default, installation is into /usr/local, but this can be changed + with the "--prefix" option when running "configure". + + You may specify the option "--sysconfdir" to set the directory + where configuration files like "named.conf" go by default, + and "--localstatedir" to set the default parent directory + of "run/named.pid". For backwards compatibility with BIND 8, + --sysconfdir defaults to "/etc" and --localstatedir defaults to + "/var" if no --prefix option is given. If there is a --prefix + option, sysconfdir defaults to "$prefix/etc" and localstatedir + defaults to "$prefix/var". + + To see additional configure options, run "configure --help". + Note that the help message does not reflect the BIND 8 + compatibility defaults for sysconfdir and localstatedir. + + If you're planning on making changes to the BIND 9 source, you + should also "make depend". If you're using Emacs, you might find + "make tags" helpful. + + If you need to re-run configure please run "make distclean" first. + This will ensure that all the option changes take. + + Building with gcc is not supported, unless gcc is the vendor's usual + compiler (e.g. the various BSD systems, Linux). + + Known compiler issues: + * gcc-3.2.1 and gcc-3.1.1 is known to cause problems with solaris-x86. + * gcc prior to gcc-3.2.3 ultrasparc generates incorrect code at -02. + * gcc-3.3.5 powerpc generates incorrect code at -02. + * Irix, MipsPRO 7.4.1m is known to cause problems. + + A limited test suite can be run with "make test". Many of + the tests require you to configure a set of virtual IP addresses + on your system, and some require Perl; see bin/tests/system/README + for details. + + SunOS 4 requires "printf" to be installed to make the shared + libraries. sh-utils-1.16 provides a "printf" which compiles + on SunOS 4. + +Documentation + + The BIND 9 Administrator Reference Manual is included with the + source distribution in DocBook XML and HTML format, in the + doc/arm directory. + + Some of the programs in the BIND 9 distribution have man pages + in their directories. In particular, the command line + options of "named" are documented in /bin/named/named.8. + There is now also a set of man pages for the lwres library. + + If you are upgrading from BIND 8, please read the migration + notes in doc/misc/migration. If you are upgrading from + BIND 4, read doc/misc/migration-4to9. + + Frequently asked questions and their answers can be found in + FAQ. + + +Bug Reports and Mailing Lists + + Bugs reports should be sent to + + bind9-bugs@isc.org + + To join the BIND Users mailing list, send mail to + + bind-users-request@isc.org + + archives of which can be found via + + http://www.isc.org/ops/lists/ + + If you're planning on making changes to the BIND 9 source + code, you might want to join the BIND Workers mailing list. + Send mail to + + bind-workers-request@isc.org + + diff --git a/contrib/bind-9.5.2/README.DELETED b/contrib/bind-9.5.2/README.DELETED new file mode 100644 index 0000000000..a3c92a7582 --- /dev/null +++ b/contrib/bind-9.5.2/README.DELETED @@ -0,0 +1,175 @@ +FAQ.xml +Makefile.in +acconfig.h +aclocal.m4 +bin/Makefile.in +bin/check/Makefile.in +bin/check/named-checkconf.docbook +bin/check/named-checkzone.docbook +bin/check/win32/ +bin/dig/Makefile.in +bin/dig/dig.docbook +bin/dig/host.docbook +bin/dig/nslookup.docbook +bin/dig/win32/ +bin/dnssec/Makefile.in +bin/dnssec/dnssec-keygen.docbook +bin/dnssec/dnssec-signzone.docbook +bin/dnssec/win32/ +bin/named/Makefile.in +bin/named/lwresd.docbook +bin/named/named.conf.docbook +bin/named/named.docbook +bin/named/unix/Makefile.in +bin/named/win32/ +bin/nsupdate/Makefile.in +bin/nsupdate/nsupdate.docbook +bin/nsupdate/win32/ +bin/rndc/Makefile.in +bin/rndc/rndc-confgen.docbook +bin/rndc/rndc.conf.docbook +bin/rndc/rndc.docbook +bin/rndc/unix/Makefile.in +bin/rndc/win32/ +bin/tests/ +bin/win32/ +config.guess +config.h.in +config.h.win32 +config.sub +config.threads.in +configure +configure.in +contrib/ +doc/ +docutil/ +install-sh +isc-config.sh.1 +isc-config.sh.docbook +isc-config.sh.html +isc-config.sh.in +lib/Makefile.in +lib/bind/Makefile.in +lib/bind/aclocal.m4 +lib/bind/bsd/Makefile.in +lib/bind/configure +lib/bind/configure.in +lib/bind/dst/Makefile.in +lib/bind/include/Makefile.in +lib/bind/inet/Makefile.in +lib/bind/irs/Makefile.in +lib/bind/isc/Makefile.in +lib/bind/nameser/Makefile.in +lib/bind/port/Makefile.in +lib/bind/port/aix32/ +lib/bind/port/aix4/ +lib/bind/port/aix5/ +lib/bind/port/aux3/ +lib/bind/port/bsdos/ +lib/bind/port/bsdos2/ +lib/bind/port/cygwin/ +lib/bind/port/darwin/ +lib/bind/port/decunix/ +lib/bind/port/freebsd/Makefile.in +lib/bind/port/freebsd/include/Makefile.in +lib/bind/port/hpux/ +lib/bind/port/hpux10/ +lib/bind/port/hpux9/ +lib/bind/port/irix/ +lib/bind/port/linux/ +lib/bind/port/lynxos/ +lib/bind/port/mpe/ +lib/bind/port/netbsd/ +lib/bind/port/next/ +lib/bind/port/openbsd/ +lib/bind/port/prand_conf/Makefile.in +lib/bind/port/qnx/ +lib/bind/port/rhapsody/ +lib/bind/port/sco42/ +lib/bind/port/sco50/ +lib/bind/port/solaris/ +lib/bind/port/sunos/ +lib/bind/port/ultrix/ +lib/bind/port/unixware20/ +lib/bind/port/unixware212/ +lib/bind/port/unixware7/ +lib/bind/port/unknown/Makefile.in +lib/bind/port/unknown/include/Makefile.in +lib/bind/resolv/Makefile.in +lib/bind9/Makefile.in +lib/bind9/include/Makefile.in +lib/bind9/include/bind9/Makefile.in +lib/bind9/win32/ +lib/dns/Makefile.in +lib/dns/include/Makefile.in +lib/dns/include/dns/Makefile.in +lib/dns/include/dst/Makefile.in +lib/dns/win32/ +lib/isc/Makefile.in +lib/isc/alpha/ +lib/isc/ia64/ +lib/isc/include/Makefile.in +lib/isc/include/isc/Makefile.in +lib/isc/mips/ +lib/isc/nls/Makefile.in +lib/isc/noatomic/Makefile.in +lib/isc/noatomic/include/Makefile.in +lib/isc/noatomic/include/isc/Makefile.in +lib/isc/nothreads/Makefile.in +lib/isc/nothreads/include/Makefile.in +lib/isc/nothreads/include/isc/Makefile.in +lib/isc/powerpc/ +lib/isc/pthreads/Makefile.in +lib/isc/pthreads/include/Makefile.in +lib/isc/pthreads/include/isc/Makefile.in +lib/isc/sparc64/ +lib/isc/unix/Makefile.in +lib/isc/unix/include/Makefile.in +lib/isc/unix/include/isc/Makefile.in +lib/isc/win32/ +lib/isc/x86_32/Makefile.in +lib/isc/x86_32/include/Makefile.in +lib/isc/x86_32/include/isc/Makefile.in +lib/isc/x86_64/Makefile.in +lib/isc/x86_64/include/Makefile.in +lib/isc/x86_64/include/isc/Makefile.in +lib/isccc/Makefile.in +lib/isccc/include/Makefile.in +lib/isccc/include/isccc/Makefile.in +lib/isccc/win32/ +lib/isccfg/Makefile.in +lib/isccfg/include/Makefile.in +lib/isccfg/include/isccfg/Makefile.in +lib/isccfg/win32/ +lib/lwres/Makefile.in +lib/lwres/include/Makefile.in +lib/lwres/include/lwres/Makefile.in +lib/lwres/man/Makefile.in +lib/lwres/man/lwres.docbook +lib/lwres/man/lwres_buffer.docbook +lib/lwres/man/lwres_config.docbook +lib/lwres/man/lwres_context.docbook +lib/lwres/man/lwres_gabn.docbook +lib/lwres/man/lwres_gai_strerror.docbook +lib/lwres/man/lwres_getaddrinfo.docbook +lib/lwres/man/lwres_gethostent.docbook +lib/lwres/man/lwres_getipnode.docbook +lib/lwres/man/lwres_getnameinfo.docbook +lib/lwres/man/lwres_getrrsetbyname.docbook +lib/lwres/man/lwres_gnba.docbook +lib/lwres/man/lwres_hstrerror.docbook +lib/lwres/man/lwres_inetntop.docbook +lib/lwres/man/lwres_noop.docbook +lib/lwres/man/lwres_packet.docbook +lib/lwres/man/lwres_resutil.docbook +lib/lwres/unix/Makefile.in +lib/lwres/unix/include/Makefile.in +lib/lwres/unix/include/lwres/Makefile.in +lib/lwres/win32/ +lib/tests/ +lib/win32/ +libtool.m4 +ltmain.sh +make/ +mkinstalldirs +win32utils/ diff --git a/contrib/bind-9.5.2/README.DRAGONFLY b/contrib/bind-9.5.2/README.DRAGONFLY new file mode 100644 index 0000000000..1fe245f218 --- /dev/null +++ b/contrib/bind-9.5.2/README.DRAGONFLY @@ -0,0 +1,58 @@ + + BIND-9.5.2 AS USED BY DRAGONFLY + + This directory contains a selected set of files from the ISC + bind-9.5.2.tar.gz distribution. No files have been moved + or modified from their extracted position. + + This distribution was downloaded from the following site: + + https://www.isc.org/downloadables/11 + + DO NOT CREATE ANY FILES IN THIS DIRECTORY HIERARCHY! THIS + HIERARCHY REPRESENTS AN EXACT COPY, MINUS UNNEEDED FILES PLUS CHANGES + IN BASE TO FIT IT INTO BASE, OF THE ORIGINAL ARCHIVE. + All modifications are made in the + DragonFly build wrapper, in: + + /usr/src/usr.sbin/named + /usr/src/usr.sbin/(various) + /usr/src/usr.bin/(various) + /usr/src/lib/libbind + /usr/src/lib/libbind9 + /usr/src/lib/libisc + + The only additional files added to this directory are README.DRAGONFLY + and README.DELETED. + + All changes to original files need to be made in base. Read development(7) + for further information. + + UPGRADE PROCEDURE: + + * download a new bind distribution + + * extract the archive into /usr/src/contrib of vendor/BIND, using the subdirectory + that the archive extracts as. + + * redirect the build directory to the new directory in base: + + /usr/src/usr.sbin/named/Makefile.inc + /usr/src/lib/libbind/Makefile + /usr/src/lib/libisc/Makefile + + * in vendor/BIND remove files that are not used (or run a build and figure out + what files are not used and remove them). + + * Add the remainder to git. + + * Once the new archive is in place, the old one can be physically + removed from the DragonFly CVS repository. The CVS meister would + have to do the physical removal. + + DO NOT MAKE ANY EDITS TO THE DISTRIBUTION IN THIS CONTRIB + DIRECTORY, OTHER THEN TO ADD OR DELETE FILES ASSOCIATED WITH THE + DISTRIBUTION. + + The file README.DELETED contains a list of deleted files. + diff --git a/contrib/bind-9.5.2/README.idnkit b/contrib/bind-9.5.2/README.idnkit new file mode 100644 index 0000000000..4cb6641339 --- /dev/null +++ b/contrib/bind-9.5.2/README.idnkit @@ -0,0 +1,112 @@ + + BIND-9 IDN patch + + Japan Network Information Center (JPNIC) + + +* What is this patch for? + +This patch adds internationalized domain name (IDN) support to BIND-9. +You'll get internationalized version of dig/host/nslookup commands. + + + internationalized dig/host/nslookup + dig/host/nslookup accepts non-ASCII domain names in the local + codeset (such as Shift JIS, Big5 or ISO8859-1) determined by + the locale information. The domain names are normalized and + converted to the encoding on the DNS protocol, and sent to DNS + servers. The replies are converted back to the local codeset + and displayed. + + +* Compilation & installation + +0. Prerequisite + +You have to build and install idnkit before building this patched version +of bind-9. + +1. Running configure script + +Run `configure' in the top directory. See `README' for the +configuration options. + +This patch adds the following 4 options to `configure'. You should +at least specify `--with-idn' option to enable IDN support. + + --with-idn[=IDN_PREFIX] + To enable IDN support, you have to specify `--with-idn' option. + The argument IDN_PREFIX is the install prefix of idnkit. If + IDN_PREFIX is omitted, PREFIX (derived from `--prefix=PREFIX') + is assumed. + + --with-libiconv[=LIBICONV_PREFIX] + Specify this option if idnkit you have installed links GNU + libiconv. The argument LIBICONV_PREFIX is install prefix of + GNU libiconv. If the argument is omitted, PREFIX (derived + from `--prefix=PREFIX') is assumed. + + `--with-libiconv' is shorthand option for GNU libiconv. + + --with-libiconv=/usr/local + + This is equivalent to: + + --with-iconv='-L/usr/local/lib -R/usr/local/lib -liconv' + + `--with-libiconv' assumes that your C compiler has `-R' + option, and that the option adds the specified run-time path + to an executable binary. If `-R' option of your compiler has + different meaning, or your compiler lacks the option, you + should use `--with-iconv' option instead. Binary command + without run-time path information might be unexecutable. + In that case, you would see an error message like: + + error in loading shared libraries: libiconv.so.2: cannot + open shared object file + + If both `--with-libiconv' and `--with-iconv' options are + specified, `--with-iconv' is prior to `--with-libiconv'. + + --with-iconv=ICONV_LIBSPEC + If your libc doesn't provide iconv(), you need to specify the + library containing iconv() with this option. `ICONV_LIBSPEC' + is the argument(s) to `cc' or `ld' to link the library, for + example, `--with-iconv="-L/usr/local/lib -liconv"'. + You don't need to specify the header file directory for "iconv.h" + to the compiler, as it isn't included directly by bind-9 with + this patch. + + --with-idnlib=IDN_LIBSPEC + With this option, you can explicitly specify the argument(s) + to `cc' or `ld' to link the idnkit's library, `libidnkit'. If + this option is not specified, `-L${PREFIX}/lib -lidnkit' is + assumed, where ${PREFIX} is the installation prefix specified + with `--with-idn' option above. You may need to use this + option to specify extra arguments, for example, + `--with-idnlib="-L/usr/local/lib -R/usr/local/lib -lidnkit"'. + +Please consult `README' for other configuration options. + +Note that if you want to specify some extra header file directories, +you should use the environment variable STD_CINCLUDES instead of +CFLAGS, as described in README. + +2. Compilation and installation + +After running "configure", just do + + make + make install + +for compiling and installing. + + +* Contact information + +Please see http//www.nic.ad.jp/en/idn/ for the latest news +about idnkit and this patch. + +Bug reports and comments on this kit should be sent to +mdnkit-bugs@nic.ad.jp and idn-cmt@nic.ad.jp, respectively. + +; $Id: README.idnkit,v 1.2.558.1 2009/01/19 00:01:09 marka Exp $ diff --git a/contrib/bind-9.5.2/bin/check/check-tool.c b/contrib/bind-9.5.2/bin/check/check-tool.c new file mode 100644 index 0000000000..c50eee328b --- /dev/null +++ b/contrib/bind-9.5.2/bin/check/check-tool.c @@ -0,0 +1,660 @@ +/* + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2002 Internet Software Consortium. + * + * 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: check-tool.c,v 1.31.62.5 2009/01/27 21:17:39 jinmei Exp $ */ + +/*! \file */ + +#include + +#include + +#include "check-tool.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifndef CHECK_SIBLING +#define CHECK_SIBLING 1 +#endif + +#ifndef CHECK_LOCAL +#define CHECK_LOCAL 1 +#endif + +#ifdef HAVE_ADDRINFO +#ifdef HAVE_GETADDRINFO +#ifdef HAVE_GAISTRERROR +#define USE_GETADDRINFO +#endif +#endif +#endif + +#define CHECK(r) \ + do { \ + result = (r); \ + if (result != ISC_R_SUCCESS) \ + goto cleanup; \ + } while (0) + +#define ERR_IS_CNAME 1 +#define ERR_NO_ADDRESSES 2 +#define ERR_LOOKUP_FAILURE 3 +#define ERR_EXTRA_A 4 +#define ERR_EXTRA_AAAA 5 +#define ERR_MISSING_GLUE 5 +#define ERR_IS_MXCNAME 6 +#define ERR_IS_SRVCNAME 7 + +static const char *dbtype[] = { "rbt" }; + +int debug = 0; +isc_boolean_t nomerge = ISC_TRUE; +#if CHECK_LOCAL +isc_boolean_t docheckmx = ISC_TRUE; +isc_boolean_t dochecksrv = ISC_TRUE; +isc_boolean_t docheckns = ISC_TRUE; +#else +isc_boolean_t docheckmx = ISC_FALSE; +isc_boolean_t dochecksrv = ISC_FALSE; +isc_boolean_t docheckns = ISC_FALSE; +#endif +unsigned int zone_options = DNS_ZONEOPT_CHECKNS | + DNS_ZONEOPT_CHECKMX | + DNS_ZONEOPT_MANYERRORS | + DNS_ZONEOPT_CHECKNAMES | + DNS_ZONEOPT_CHECKINTEGRITY | +#if CHECK_SIBLING + DNS_ZONEOPT_CHECKSIBLING | +#endif + DNS_ZONEOPT_CHECKWILDCARD | + DNS_ZONEOPT_WARNMXCNAME | + DNS_ZONEOPT_WARNSRVCNAME; + +/* + * This needs to match the list in bin/named/log.c. + */ +static isc_logcategory_t categories[] = { + { "", 0 }, + { "client", 0 }, + { "network", 0 }, + { "update", 0 }, + { "queries", 0 }, + { "unmatched", 0 }, + { "update-security", 0 }, + { "query-errors", 0 }, + { NULL, 0 } +}; + +static isc_symtab_t *symtab = NULL; +static isc_mem_t *sym_mctx; + +static void +freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) { + UNUSED(type); + UNUSED(value); + isc_mem_free(userarg, key); +} + +static void +add(char *key, int value) { + isc_result_t result; + isc_symvalue_t symvalue; + + if (sym_mctx == NULL) { + result = isc_mem_create(0, 0, &sym_mctx); + if (result != ISC_R_SUCCESS) + return; + } + + if (symtab == NULL) { + result = isc_symtab_create(sym_mctx, 100, freekey, sym_mctx, + ISC_FALSE, &symtab); + if (result != ISC_R_SUCCESS) + return; + } + + key = isc_mem_strdup(sym_mctx, key); + if (key == NULL) + return; + + symvalue.as_pointer = NULL; + result = isc_symtab_define(symtab, key, value, symvalue, + isc_symexists_reject); + if (result != ISC_R_SUCCESS) + isc_mem_free(sym_mctx, key); +} + +static isc_boolean_t +logged(char *key, int value) { + isc_result_t result; + + if (symtab == NULL) + return (ISC_FALSE); + + result = isc_symtab_lookup(symtab, key, value, NULL); + if (result == ISC_R_SUCCESS) + return (ISC_TRUE); + return (ISC_FALSE); +} + +static isc_boolean_t +checkns(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner, + dns_rdataset_t *a, dns_rdataset_t *aaaa) +{ +#ifdef USE_GETADDRINFO + dns_rdataset_t *rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + struct addrinfo hints, *ai, *cur; + char namebuf[DNS_NAME_FORMATSIZE + 1]; + char ownerbuf[DNS_NAME_FORMATSIZE]; + char addrbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123")]; + isc_boolean_t answer = ISC_TRUE; + isc_boolean_t match; + const char *type; + void *ptr = NULL; + int result; + + REQUIRE(a == NULL || !dns_rdataset_isassociated(a) || + a->type == dns_rdatatype_a); + REQUIRE(aaaa == NULL || !dns_rdataset_isassociated(aaaa) || + aaaa->type == dns_rdatatype_aaaa); + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + dns_name_format(name, namebuf, sizeof(namebuf) - 1); + /* + * Turn off search. + */ + if (dns_name_countlabels(name) > 1U) + strcat(namebuf, "."); + dns_name_format(owner, ownerbuf, sizeof(ownerbuf)); + + result = getaddrinfo(namebuf, NULL, &hints, &ai); + dns_name_format(name, namebuf, sizeof(namebuf) - 1); + switch (result) { + case 0: + /* + * Work around broken getaddrinfo() implementations that + * fail to set ai_canonname on first entry. + */ + cur = ai; + while (cur != NULL && cur->ai_canonname == NULL && + cur->ai_next != NULL) + cur = cur->ai_next; + if (cur != NULL && cur->ai_canonname != NULL && + strcasecmp(cur->ai_canonname, namebuf) != 0 && + !logged(namebuf, ERR_IS_CNAME)) { + dns_zone_log(zone, ISC_LOG_ERROR, + "%s/NS '%s' (out of zone) " + "is a CNAME (illegal)", + ownerbuf, namebuf); + /* XXX950 make fatal for 9.5.0 */ + /* answer = ISC_FALSE; */ + add(namebuf, ERR_IS_CNAME); + } + break; + case EAI_NONAME: +#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) + case EAI_NODATA: +#endif + if (!logged(namebuf, ERR_NO_ADDRESSES)) { + dns_zone_log(zone, ISC_LOG_ERROR, + "%s/NS '%s' (out of zone) " + "has no addresses records (A or AAAA)", + ownerbuf, namebuf); + add(namebuf, ERR_NO_ADDRESSES); + } + /* XXX950 make fatal for 9.5.0 */ + return (ISC_TRUE); + + default: + if (!logged(namebuf, ERR_LOOKUP_FAILURE)) { + dns_zone_log(zone, ISC_LOG_WARNING, + "getaddrinfo(%s) failed: %s", + namebuf, gai_strerror(result)); + add(namebuf, ERR_LOOKUP_FAILURE); + } + return (ISC_TRUE); + } + if (a == NULL || aaaa == NULL) + return (answer); + /* + * Check that all glue records really exist. + */ + if (!dns_rdataset_isassociated(a)) + goto checkaaaa; + result = dns_rdataset_first(a); + while (result == ISC_R_SUCCESS) { + dns_rdataset_current(a, &rdata); + match = ISC_FALSE; + for (cur = ai; cur != NULL; cur = cur->ai_next) { + if (cur->ai_family != AF_INET) + continue; + ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr; + if (memcmp(ptr, rdata.data, rdata.length) == 0) { + match = ISC_TRUE; + break; + } + } + if (!match && !logged(namebuf, ERR_EXTRA_A)) { + dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' " + "extra GLUE A record (%s)", + ownerbuf, namebuf, + inet_ntop(AF_INET, rdata.data, + addrbuf, sizeof(addrbuf))); + add(namebuf, ERR_EXTRA_A); + /* XXX950 make fatal for 9.5.0 */ + /* answer = ISC_FALSE; */ + } + dns_rdata_reset(&rdata); + result = dns_rdataset_next(a); + } + + checkaaaa: + if (!dns_rdataset_isassociated(aaaa)) + goto checkmissing; + result = dns_rdataset_first(aaaa); + while (result == ISC_R_SUCCESS) { + dns_rdataset_current(aaaa, &rdata); + match = ISC_FALSE; + for (cur = ai; cur != NULL; cur = cur->ai_next) { + if (cur->ai_family != AF_INET6) + continue; + ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr; + if (memcmp(ptr, rdata.data, rdata.length) == 0) { + match = ISC_TRUE; + break; + } + } + if (!match && !logged(namebuf, ERR_EXTRA_AAAA)) { + dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' " + "extra GLUE AAAA record (%s)", + ownerbuf, namebuf, + inet_ntop(AF_INET6, rdata.data, + addrbuf, sizeof(addrbuf))); + add(namebuf, ERR_EXTRA_AAAA); + /* XXX950 make fatal for 9.5.0. */ + /* answer = ISC_FALSE; */ + } + dns_rdata_reset(&rdata); + result = dns_rdataset_next(aaaa); + } + + checkmissing: + /* + * Check that all addresses appear in the glue. + */ + if (!logged(namebuf, ERR_MISSING_GLUE)) { + isc_boolean_t missing_glue = ISC_FALSE; + for (cur = ai; cur != NULL; cur = cur->ai_next) { + switch (cur->ai_family) { + case AF_INET: + rdataset = a; + ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr; + type = "A"; + break; + case AF_INET6: + rdataset = aaaa; + ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr; + type = "AAAA"; + break; + default: + continue; + } + match = ISC_FALSE; + if (dns_rdataset_isassociated(rdataset)) + result = dns_rdataset_first(rdataset); + else + result = ISC_R_FAILURE; + while (result == ISC_R_SUCCESS && !match) { + dns_rdataset_current(rdataset, &rdata); + if (memcmp(ptr, rdata.data, rdata.length) == 0) + match = ISC_TRUE; + dns_rdata_reset(&rdata); + result = dns_rdataset_next(rdataset); + } + if (!match) { + dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' " + "missing GLUE %s record (%s)", + ownerbuf, namebuf, type, + inet_ntop(cur->ai_family, ptr, + addrbuf, sizeof(addrbuf))); + /* XXX950 make fatal for 9.5.0. */ + /* answer = ISC_FALSE; */ + missing_glue = ISC_TRUE; + } + } + if (missing_glue) + add(namebuf, ERR_MISSING_GLUE); + } + freeaddrinfo(ai); + return (answer); +#else + return (ISC_TRUE); +#endif +} + +static isc_boolean_t +checkmx(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) { +#ifdef USE_GETADDRINFO + struct addrinfo hints, *ai, *cur; + char namebuf[DNS_NAME_FORMATSIZE + 1]; + char ownerbuf[DNS_NAME_FORMATSIZE]; + int result; + int level = ISC_LOG_ERROR; + isc_boolean_t answer = ISC_TRUE; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + dns_name_format(name, namebuf, sizeof(namebuf) - 1); + /* + * Turn off search. + */ + if (dns_name_countlabels(name) > 1U) + strcat(namebuf, "."); + dns_name_format(owner, ownerbuf, sizeof(ownerbuf)); + + result = getaddrinfo(namebuf, NULL, &hints, &ai); + dns_name_format(name, namebuf, sizeof(namebuf) - 1); + switch (result) { + case 0: + /* + * Work around broken getaddrinfo() implementations that + * fail to set ai_canonname on first entry. + */ + cur = ai; + while (cur != NULL && cur->ai_canonname == NULL && + cur->ai_next != NULL) + cur = cur->ai_next; + if (cur != NULL && cur->ai_canonname != NULL && + strcasecmp(cur->ai_canonname, namebuf) != 0) { + if ((zone_options & DNS_ZONEOPT_WARNMXCNAME) != 0) + level = ISC_LOG_WARNING; + if ((zone_options & DNS_ZONEOPT_IGNOREMXCNAME) == 0) { + if (!logged(namebuf, ERR_IS_MXCNAME)) { + dns_zone_log(zone, level, + "%s/MX '%s' (out of zone)" + " is a CNAME (illegal)", + ownerbuf, namebuf); + add(namebuf, ERR_IS_MXCNAME); + } + if (level == ISC_LOG_ERROR) + answer = ISC_FALSE; + } + } + freeaddrinfo(ai); + return (answer); + + case EAI_NONAME: +#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) + case EAI_NODATA: +#endif + if (!logged(namebuf, ERR_NO_ADDRESSES)) { + dns_zone_log(zone, ISC_LOG_ERROR, + "%s/MX '%s' (out of zone) " + "has no addresses records (A or AAAA)", + ownerbuf, namebuf); + add(namebuf, ERR_NO_ADDRESSES); + } + /* XXX950 make fatal for 9.5.0. */ + return (ISC_TRUE); + + default: + if (!logged(namebuf, ERR_LOOKUP_FAILURE)) { + dns_zone_log(zone, ISC_LOG_WARNING, + "getaddrinfo(%s) failed: %s", + namebuf, gai_strerror(result)); + add(namebuf, ERR_LOOKUP_FAILURE); + } + return (ISC_TRUE); + } +#else + return (ISC_TRUE); +#endif +} + +static isc_boolean_t +checksrv(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) { +#ifdef USE_GETADDRINFO + struct addrinfo hints, *ai, *cur; + char namebuf[DNS_NAME_FORMATSIZE + 1]; + char ownerbuf[DNS_NAME_FORMATSIZE]; + int result; + int level = ISC_LOG_ERROR; + isc_boolean_t answer = ISC_TRUE; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + dns_name_format(name, namebuf, sizeof(namebuf) - 1); + /* + * Turn off search. + */ + if (dns_name_countlabels(name) > 1U) + strcat(namebuf, "."); + dns_name_format(owner, ownerbuf, sizeof(ownerbuf)); + + result = getaddrinfo(namebuf, NULL, &hints, &ai); + dns_name_format(name, namebuf, sizeof(namebuf) - 1); + switch (result) { + case 0: + /* + * Work around broken getaddrinfo() implementations that + * fail to set ai_canonname on first entry. + */ + cur = ai; + while (cur != NULL && cur->ai_canonname == NULL && + cur->ai_next != NULL) + cur = cur->ai_next; + if (cur != NULL && cur->ai_canonname != NULL && + strcasecmp(cur->ai_canonname, namebuf) != 0) { + if ((zone_options & DNS_ZONEOPT_WARNSRVCNAME) != 0) + level = ISC_LOG_WARNING; + if ((zone_options & DNS_ZONEOPT_IGNORESRVCNAME) == 0) { + if (!logged(namebuf, ERR_IS_SRVCNAME)) { + dns_zone_log(zone, level, "%s/SRV '%s'" + " (out of zone) is a " + "CNAME (illegal)", + ownerbuf, namebuf); + add(namebuf, ERR_IS_SRVCNAME); + } + if (level == ISC_LOG_ERROR) + answer = ISC_FALSE; + } + } + freeaddrinfo(ai); + return (answer); + + case EAI_NONAME: +#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) + case EAI_NODATA: +#endif + if (!logged(namebuf, ERR_NO_ADDRESSES)) { + dns_zone_log(zone, ISC_LOG_ERROR, + "%s/SRV '%s' (out of zone) " + "has no addresses records (A or AAAA)", + ownerbuf, namebuf); + add(namebuf, ERR_NO_ADDRESSES); + } + /* XXX950 make fatal for 9.5.0. */ + return (ISC_TRUE); + + default: + if (!logged(namebuf, ERR_LOOKUP_FAILURE)) { + dns_zone_log(zone, ISC_LOG_WARNING, + "getaddrinfo(%s) failed: %s", + namebuf, gai_strerror(result)); + add(namebuf, ERR_LOOKUP_FAILURE); + } + return (ISC_TRUE); + } +#else + return (ISC_TRUE); +#endif +} + +isc_result_t +setup_logging(isc_mem_t *mctx, FILE *errout, isc_log_t **logp) { + isc_logdestination_t destination; + isc_logconfig_t *logconfig = NULL; + isc_log_t *log = NULL; + + RUNTIME_CHECK(isc_log_create(mctx, &log, &logconfig) == ISC_R_SUCCESS); + isc_log_registercategories(log, categories); + isc_log_setcontext(log); + dns_log_init(log); + dns_log_setcontext(log); + cfg_log_init(log); + + destination.file.stream = errout; + destination.file.name = NULL; + destination.file.versions = ISC_LOG_ROLLNEVER; + destination.file.maximum_size = 0; + RUNTIME_CHECK(isc_log_createchannel(logconfig, "stderr", + ISC_LOG_TOFILEDESC, + ISC_LOG_DYNAMIC, + &destination, 0) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_log_usechannel(logconfig, "stderr", + NULL, NULL) == ISC_R_SUCCESS); + + *logp = log; + return (ISC_R_SUCCESS); +} + +/*% load the zone */ +isc_result_t +load_zone(isc_mem_t *mctx, const char *zonename, const char *filename, + dns_masterformat_t fileformat, const char *classname, + dns_zone_t **zonep) +{ + isc_result_t result; + dns_rdataclass_t rdclass; + isc_textregion_t region; + isc_buffer_t buffer; + dns_fixedname_t fixorigin; + dns_name_t *origin; + dns_zone_t *zone = NULL; + + REQUIRE(zonep == NULL || *zonep == NULL); + + if (debug) + fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n", + zonename, filename, classname); + + CHECK(dns_zone_create(&zone, mctx)); + + dns_zone_settype(zone, dns_zone_master); + + isc_buffer_init(&buffer, zonename, strlen(zonename)); + isc_buffer_add(&buffer, strlen(zonename)); + dns_fixedname_init(&fixorigin); + origin = dns_fixedname_name(&fixorigin); + CHECK(dns_name_fromtext(origin, &buffer, dns_rootname, + ISC_FALSE, NULL)); + CHECK(dns_zone_setorigin(zone, origin)); + CHECK(dns_zone_setdbtype(zone, 1, (const char * const *) dbtype)); + CHECK(dns_zone_setfile2(zone, filename, fileformat)); + + DE_CONST(classname, region.base); + region.length = strlen(classname); + CHECK(dns_rdataclass_fromtext(&rdclass, ®ion)); + + dns_zone_setclass(zone, rdclass); + dns_zone_setoption(zone, zone_options, ISC_TRUE); + dns_zone_setoption(zone, DNS_ZONEOPT_NOMERGE, nomerge); + if (docheckmx) + dns_zone_setcheckmx(zone, checkmx); + if (docheckns) + dns_zone_setcheckns(zone, checkns); + if (dochecksrv) + dns_zone_setchecksrv(zone, checksrv); + + CHECK(dns_zone_load(zone)); + if (zonep != NULL) { + *zonep = zone; + zone = NULL; + } + + cleanup: + if (zone != NULL) + dns_zone_detach(&zone); + return (result); +} + +/*% dump the zone */ +isc_result_t +dump_zone(const char *zonename, dns_zone_t *zone, const char *filename, + dns_masterformat_t fileformat, const dns_master_style_t *style) +{ + isc_result_t result; + FILE *output = stdout; + + if (debug) { + if (filename != NULL && strcmp(filename, "-") != 0) + fprintf(stderr, "dumping \"%s\" to \"%s\"\n", + zonename, filename); + else + fprintf(stderr, "dumping \"%s\"\n", zonename); + } + + if (filename != NULL && strcmp(filename, "-") != 0) { + result = isc_stdio_open(filename, "w+", &output); + + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not open output " + "file \"%s\" for writing\n", filename); + return (ISC_R_FAILURE); + } + } + + result = dns_zone_dumptostream2(zone, output, fileformat, style); + + if (output != stdout) + (void)isc_stdio_close(output); + + return (result); +} diff --git a/contrib/bind-9.5.2/bin/check/check-tool.h b/contrib/bind-9.5.2/bin/check/check-tool.h new file mode 100644 index 0000000000..b0ba7e06ef --- /dev/null +++ b/contrib/bind-9.5.2/bin/check/check-tool.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2002 Internet Software Consortium. + * + * 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: check-tool.h,v 1.14 2007/06/18 23:47:17 tbox Exp $ */ + +#ifndef CHECK_TOOL_H +#define CHECK_TOOL_H + +/*! \file */ + +#include +#include +#include + +#include +#include + +ISC_LANG_BEGINDECLS + +isc_result_t +setup_logging(isc_mem_t *mctx, FILE *errout, isc_log_t **logp); + +isc_result_t +load_zone(isc_mem_t *mctx, const char *zonename, const char *filename, + dns_masterformat_t fileformat, const char *classname, + dns_zone_t **zonep); + +isc_result_t +dump_zone(const char *zonename, dns_zone_t *zone, const char *filename, + dns_masterformat_t fileformat, const dns_master_style_t *style); + +extern int debug; +extern isc_boolean_t nomerge; +extern isc_boolean_t docheckmx; +extern isc_boolean_t docheckns; +extern isc_boolean_t dochecksrv; +extern unsigned int zone_options; + +ISC_LANG_ENDDECLS + +#endif diff --git a/contrib/bind-9.5.2/bin/check/named-checkconf.8 b/contrib/bind-9.5.2/bin/check/named-checkconf.8 new file mode 100644 index 0000000000..84b2d302a4 --- /dev/null +++ b/contrib/bind-9.5.2/bin/check/named-checkconf.8 @@ -0,0 +1,94 @@ +.\" Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2000-2002 Internet Software Consortium. +.\" +.\" 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: named-checkconf.8,v 1.30.130.1 2009/07/11 01:43:26 tbox Exp $ +.\" +.hy 0 +.ad l +.\" Title: named\-checkconf +.\" Author: +.\" Generator: DocBook XSL Stylesheets v1.71.1 +.\" Date: June 14, 2000 +.\" Manual: BIND9 +.\" Source: BIND9 +.\" +.TH "NAMED\-CHECKCONF" "8" "June 14, 2000" "BIND9" "BIND9" +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.SH "NAME" +named\-checkconf \- named configuration file syntax checking tool +.SH "SYNOPSIS" +.HP 16 +\fBnamed\-checkconf\fR [\fB\-h\fR] [\fB\-v\fR] [\fB\-j\fR] [\fB\-t\ \fR\fB\fIdirectory\fR\fR] {filename} [\fB\-z\fR] +.SH "DESCRIPTION" +.PP +\fBnamed\-checkconf\fR +checks the syntax, but not the semantics, of a named configuration file. +.SH "OPTIONS" +.PP +\-h +.RS 4 +Print the usage summary and exit. +.RE +.PP +\-t \fIdirectory\fR +.RS 4 +Chroot to +\fIdirectory\fR +so that include directives in the configuration file are processed as if run by a similarly chrooted named. +.RE +.PP +\-v +.RS 4 +Print the version of the +\fBnamed\-checkconf\fR +program and exit. +.RE +.PP +\-z +.RS 4 +Perform a test load of all master zones found in +\fInamed.conf\fR. +.RE +.PP +\-j +.RS 4 +When loading a zonefile read the journal if it exists. +.RE +.PP +filename +.RS 4 +The name of the configuration file to be checked. If not specified, it defaults to +\fI/etc/named.conf\fR. +.RE +.SH "RETURN VALUES" +.PP +\fBnamed\-checkconf\fR +returns an exit status of 1 if errors were detected and 0 otherwise. +.SH "SEE ALSO" +.PP +\fBnamed\fR(8), +\fBnamed\-checkzone\fR(8), +BIND 9 Administrator Reference Manual. +.SH "AUTHOR" +.PP +Internet Systems Consortium +.SH "COPYRIGHT" +Copyright \(co 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") +.br +Copyright \(co 2000\-2002 Internet Software Consortium. +.br diff --git a/contrib/bind-9.5.2/bin/check/named-checkconf.c b/contrib/bind-9.5.2/bin/check/named-checkconf.c new file mode 100644 index 0000000000..57cc20cefc --- /dev/null +++ b/contrib/bind-9.5.2/bin/check/named-checkconf.c @@ -0,0 +1,498 @@ +/* + * 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 + * 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: named-checkconf.c,v 1.46.18.2 2009/02/16 23:46:44 tbox Exp $ */ + +/*! \file */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#include "check-tool.h" + +static const char *program = "named-checkconf"; + +isc_log_t *logc = NULL; + +#define CHECK(r)\ + do { \ + result = (r); \ + if (result != ISC_R_SUCCESS) \ + goto cleanup; \ + } while (0) + +/*% usage */ +static void +usage(void) { + fprintf(stderr, "usage: %s [-h] [-j] [-v] [-z] [-t directory] " + "[named.conf]\n", program); + exit(1); +} + +/*% directory callback */ +static isc_result_t +directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) { + isc_result_t result; + const char *directory; + + REQUIRE(strcasecmp("directory", clausename) == 0); + + UNUSED(arg); + UNUSED(clausename); + + /* + * Change directory. + */ + directory = cfg_obj_asstring(obj); + result = isc_dir_chdir(directory); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(obj, logc, ISC_LOG_ERROR, + "change directory to '%s' failed: %s\n", + directory, isc_result_totext(result)); + return (result); + } + + return (ISC_R_SUCCESS); +} + +static isc_boolean_t +get_maps(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) { + int i; + for (i = 0;; i++) { + if (maps[i] == NULL) + return (ISC_FALSE); + if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS) + return (ISC_TRUE); + } +} + +static isc_boolean_t +get_checknames(const cfg_obj_t **maps, const cfg_obj_t **obj) { + const cfg_listelt_t *element; + const cfg_obj_t *checknames; + const cfg_obj_t *type; + const cfg_obj_t *value; + isc_result_t result; + int i; + + for (i = 0;; i++) { + if (maps[i] == NULL) + return (ISC_FALSE); + checknames = NULL; + result = cfg_map_get(maps[i], "check-names", &checknames); + if (result != ISC_R_SUCCESS) + continue; + if (checknames != NULL && !cfg_obj_islist(checknames)) { + *obj = checknames; + return (ISC_TRUE); + } + for (element = cfg_list_first(checknames); + element != NULL; + element = cfg_list_next(element)) { + value = cfg_listelt_value(element); + type = cfg_tuple_get(value, "type"); + if (strcasecmp(cfg_obj_asstring(type), "master") != 0) + continue; + *obj = cfg_tuple_get(value, "mode"); + return (ISC_TRUE); + } + } +} + +static isc_result_t +config_get(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) { + int i; + + for (i = 0;; i++) { + if (maps[i] == NULL) + return (ISC_R_NOTFOUND); + if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS) + return (ISC_R_SUCCESS); + } +} + +/*% configure the zone */ +static isc_result_t +configure_zone(const char *vclass, const char *view, + const cfg_obj_t *zconfig, const cfg_obj_t *vconfig, + const cfg_obj_t *config, isc_mem_t *mctx) +{ + int i = 0; + isc_result_t result; + const char *zclass; + const char *zname; + const char *zfile; + const cfg_obj_t *maps[4]; + const cfg_obj_t *zoptions = NULL; + const cfg_obj_t *classobj = NULL; + const cfg_obj_t *typeobj = NULL; + const cfg_obj_t *fileobj = NULL; + const cfg_obj_t *dbobj = NULL; + const cfg_obj_t *obj = NULL; + const cfg_obj_t *fmtobj = NULL; + dns_masterformat_t masterformat; + + zone_options = DNS_ZONEOPT_CHECKNS | DNS_ZONEOPT_MANYERRORS; + + zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); + classobj = cfg_tuple_get(zconfig, "class"); + if (!cfg_obj_isstring(classobj)) + zclass = vclass; + else + zclass = cfg_obj_asstring(classobj); + + zoptions = cfg_tuple_get(zconfig, "options"); + maps[i++] = zoptions; + if (vconfig != NULL) + maps[i++] = cfg_tuple_get(vconfig, "options"); + if (config != NULL) { + cfg_map_get(config, "options", &obj); + if (obj != NULL) + maps[i++] = obj; + } + maps[i++] = NULL; + + cfg_map_get(zoptions, "type", &typeobj); + if (typeobj == NULL) + return (ISC_R_FAILURE); + if (strcasecmp(cfg_obj_asstring(typeobj), "master") != 0) + return (ISC_R_SUCCESS); + cfg_map_get(zoptions, "database", &dbobj); + if (dbobj != NULL) + return (ISC_R_SUCCESS); + cfg_map_get(zoptions, "file", &fileobj); + if (fileobj == NULL) + return (ISC_R_FAILURE); + zfile = cfg_obj_asstring(fileobj); + + obj = NULL; + if (get_maps(maps, "check-mx", &obj)) { + if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { + zone_options |= DNS_ZONEOPT_CHECKMX; + zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL; + } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { + zone_options |= DNS_ZONEOPT_CHECKMX; + zone_options |= DNS_ZONEOPT_CHECKMXFAIL; + } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { + zone_options &= ~DNS_ZONEOPT_CHECKMX; + zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL; + } else + INSIST(0); + } else { + zone_options |= DNS_ZONEOPT_CHECKMX; + zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL; + } + + obj = NULL; + if (get_maps(maps, "check-integrity", &obj)) { + if (cfg_obj_asboolean(obj)) + zone_options |= DNS_ZONEOPT_CHECKINTEGRITY; + else + zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY; + } else + zone_options |= DNS_ZONEOPT_CHECKINTEGRITY; + + obj = NULL; + if (get_maps(maps, "check-mx-cname", &obj)) { + if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { + zone_options |= DNS_ZONEOPT_WARNMXCNAME; + zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME; + } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { + zone_options &= ~DNS_ZONEOPT_WARNMXCNAME; + zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME; + } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { + zone_options |= DNS_ZONEOPT_WARNMXCNAME; + zone_options |= DNS_ZONEOPT_IGNOREMXCNAME; + } else + INSIST(0); + } else { + zone_options |= DNS_ZONEOPT_WARNMXCNAME; + zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME; + } + + obj = NULL; + if (get_maps(maps, "check-srv-cname", &obj)) { + if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { + zone_options |= DNS_ZONEOPT_WARNSRVCNAME; + zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME; + } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { + zone_options &= ~DNS_ZONEOPT_WARNSRVCNAME; + zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME; + } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { + zone_options |= DNS_ZONEOPT_WARNSRVCNAME; + zone_options |= DNS_ZONEOPT_IGNORESRVCNAME; + } else + INSIST(0); + } else { + zone_options |= DNS_ZONEOPT_WARNSRVCNAME; + zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME; + } + + obj = NULL; + if (get_maps(maps, "check-sibling", &obj)) { + if (cfg_obj_asboolean(obj)) + zone_options |= DNS_ZONEOPT_CHECKSIBLING; + else + zone_options &= ~DNS_ZONEOPT_CHECKSIBLING; + } + + obj = NULL; + if (get_checknames(maps, &obj)) { + if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { + zone_options |= DNS_ZONEOPT_CHECKNAMES; + zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL; + } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { + zone_options |= DNS_ZONEOPT_CHECKNAMES; + zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL; + } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { + zone_options &= ~DNS_ZONEOPT_CHECKNAMES; + zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL; + } else + INSIST(0); + } else { + zone_options |= DNS_ZONEOPT_CHECKNAMES; + zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL; + } + + masterformat = dns_masterformat_text; + fmtobj = NULL; + result = config_get(maps, "masterfile-format", &fmtobj); + if (result == ISC_R_SUCCESS) { + const char *masterformatstr = cfg_obj_asstring(fmtobj); + if (strcasecmp(masterformatstr, "text") == 0) + masterformat = dns_masterformat_text; + else if (strcasecmp(masterformatstr, "raw") == 0) + masterformat = dns_masterformat_raw; + else + INSIST(0); + } + + result = load_zone(mctx, zname, zfile, masterformat, zclass, NULL); + if (result != ISC_R_SUCCESS) + fprintf(stderr, "%s/%s/%s: %s\n", view, zname, zclass, + dns_result_totext(result)); + return(result); +} + +/*% configure a view */ +static isc_result_t +configure_view(const char *vclass, const char *view, const cfg_obj_t *config, + const cfg_obj_t *vconfig, isc_mem_t *mctx) +{ + const cfg_listelt_t *element; + const cfg_obj_t *voptions; + const cfg_obj_t *zonelist; + isc_result_t result = ISC_R_SUCCESS; + isc_result_t tresult; + + voptions = NULL; + if (vconfig != NULL) + voptions = cfg_tuple_get(vconfig, "options"); + + zonelist = NULL; + if (voptions != NULL) + (void)cfg_map_get(voptions, "zone", &zonelist); + else + (void)cfg_map_get(config, "zone", &zonelist); + + for (element = cfg_list_first(zonelist); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *zconfig = cfg_listelt_value(element); + tresult = configure_zone(vclass, view, zconfig, vconfig, + config, mctx); + if (tresult != ISC_R_SUCCESS) + result = tresult; + } + return (result); +} + + +/*% load zones from the configuration */ +static isc_result_t +load_zones_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx) { + const cfg_listelt_t *element; + const cfg_obj_t *classobj; + const cfg_obj_t *views; + const cfg_obj_t *vconfig; + const char *vclass; + isc_result_t result = ISC_R_SUCCESS; + isc_result_t tresult; + + views = NULL; + + (void)cfg_map_get(config, "view", &views); + for (element = cfg_list_first(views); + element != NULL; + element = cfg_list_next(element)) + { + const char *vname; + + vclass = "IN"; + vconfig = cfg_listelt_value(element); + if (vconfig != NULL) { + classobj = cfg_tuple_get(vconfig, "class"); + if (cfg_obj_isstring(classobj)) + vclass = cfg_obj_asstring(classobj); + } + vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name")); + tresult = configure_view(vclass, vname, config, vconfig, mctx); + if (tresult != ISC_R_SUCCESS) + result = tresult; + } + + if (views == NULL) { + tresult = configure_view("IN", "_default", config, NULL, mctx); + if (tresult != ISC_R_SUCCESS) + result = tresult; + } + return (result); +} + +/*% The main processing routine */ +int +main(int argc, char **argv) { + int c; + cfg_parser_t *parser = NULL; + cfg_obj_t *config = NULL; + const char *conffile = NULL; + isc_mem_t *mctx = NULL; + isc_result_t result; + int exit_status = 0; + isc_entropy_t *ectx = NULL; + isc_boolean_t load_zones = ISC_FALSE; + + isc_commandline_errprint = ISC_FALSE; + + while ((c = isc_commandline_parse(argc, argv, "dhjt:vz")) != EOF) { + switch (c) { + case 'd': + debug++; + break; + + case 'j': + nomerge = ISC_FALSE; + break; + + case 't': + result = isc_dir_chroot(isc_commandline_argument); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "isc_dir_chroot: %s\n", + isc_result_totext(result)); + exit(1); + } + break; + + case 'v': + printf(VERSION "\n"); + exit(0); + + case 'z': + load_zones = ISC_TRUE; + docheckmx = ISC_FALSE; + docheckns = ISC_FALSE; + dochecksrv = ISC_FALSE; + break; + + case '?': + if (isc_commandline_option != '?') + fprintf(stderr, "%s: invalid argument -%c\n", + program, isc_commandline_option); + case 'h': + usage(); + + default: + fprintf(stderr, "%s: unhandled option -%c\n", + program, isc_commandline_option); + exit(1); + } + } + + if (isc_commandline_index + 1 < argc) + usage(); + if (argv[isc_commandline_index] != NULL) + conffile = argv[isc_commandline_index]; + if (conffile == NULL || conffile[0] == '\0') + conffile = NAMED_CONFFILE; + + RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS); + + RUNTIME_CHECK(setup_logging(mctx, stdout, &logc) == ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_entropy_create(mctx, &ectx) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE) + == ISC_R_SUCCESS); + + dns_result_register(); + + RUNTIME_CHECK(cfg_parser_create(mctx, logc, &parser) == ISC_R_SUCCESS); + + cfg_parser_setcallback(parser, directory_callback, NULL); + + if (cfg_parse_file(parser, conffile, &cfg_type_namedconf, &config) != + ISC_R_SUCCESS) + exit(1); + + result = bind9_check_namedconf(config, logc, mctx); + if (result != ISC_R_SUCCESS) + exit_status = 1; + + if (result == ISC_R_SUCCESS && load_zones) { + result = load_zones_fromconfig(config, mctx); + if (result != ISC_R_SUCCESS) + exit_status = 1; + } + + cfg_obj_destroy(parser, &config); + + cfg_parser_destroy(&parser); + + dns_name_destroy(); + + isc_log_destroy(&logc); + + isc_hash_destroy(); + isc_entropy_detach(&ectx); + + isc_mem_destroy(&mctx); + + return (exit_status); +} diff --git a/contrib/bind-9.5.2/bin/check/named-checkconf.html b/contrib/bind-9.5.2/bin/check/named-checkconf.html new file mode 100644 index 0000000000..3b17022ff9 --- /dev/null +++ b/contrib/bind-9.5.2/bin/check/named-checkconf.html @@ -0,0 +1,96 @@ + + + + + +named-checkconf + + +
+
+
+

Name

+

named-checkconf — named configuration file syntax checking tool

+
+
+

Synopsis

+

named-checkconf [-h] [-v] [-j] [-t directory] {filename} [-z]

+
+
+

DESCRIPTION

+

named-checkconf + checks the syntax, but not the semantics, of a named + configuration file. +

+
+
+

OPTIONS

+
+
-h
+

+ Print the usage summary and exit. +

+
-t directory
+

+ Chroot to directory so that + include + directives in the configuration file are processed as if + run by a similarly chrooted named. +

+
-v
+

+ Print the version of the named-checkconf + program and exit. +

+
-z
+

+ Perform a test load of all master zones found in + named.conf. +

+
-j
+

+ When loading a zonefile read the journal if it exists. +

+
filename
+

+ The name of the configuration file to be checked. If not + specified, it defaults to /etc/named.conf. +

+
+
+
+

RETURN VALUES

+

named-checkconf + returns an exit status of 1 if + errors were detected and 0 otherwise. +

+
+
+

SEE ALSO

+

named(8), + named-checkzone(8), + BIND 9 Administrator Reference Manual. +

+
+
+

AUTHOR

+

Internet Systems Consortium +

+
+
+ diff --git a/contrib/bind-9.5.2/bin/check/named-checkzone.8 b/contrib/bind-9.5.2/bin/check/named-checkzone.8 new file mode 100644 index 0000000000..8e69900187 --- /dev/null +++ b/contrib/bind-9.5.2/bin/check/named-checkzone.8 @@ -0,0 +1,278 @@ +.\" Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2000-2002 Internet Software Consortium. +.\" +.\" 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: named-checkzone.8,v 1.42.130.2 2009/07/11 01:43:26 tbox Exp $ +.\" +.hy 0 +.ad l +.\" Title: named\-checkzone +.\" Author: +.\" Generator: DocBook XSL Stylesheets v1.71.1 +.\" Date: June 13, 2000 +.\" Manual: BIND9 +.\" Source: BIND9 +.\" +.TH "NAMED\-CHECKZONE" "8" "June 13, 2000" "BIND9" "BIND9" +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.SH "NAME" +named\-checkzone, named\-compilezone \- zone file validity checking or converting tool +.SH "SYNOPSIS" +.HP 16 +\fBnamed\-checkzone\fR [\fB\-d\fR] [\fB\-h\fR] [\fB\-j\fR] [\fB\-q\fR] [\fB\-v\fR] [\fB\-c\ \fR\fB\fIclass\fR\fR] [\fB\-f\ \fR\fB\fIformat\fR\fR] [\fB\-F\ \fR\fB\fIformat\fR\fR] [\fB\-i\ \fR\fB\fImode\fR\fR] [\fB\-k\ \fR\fB\fImode\fR\fR] [\fB\-m\ \fR\fB\fImode\fR\fR] [\fB\-M\ \fR\fB\fImode\fR\fR] [\fB\-n\ \fR\fB\fImode\fR\fR] [\fB\-o\ \fR\fB\fIfilename\fR\fR] [\fB\-s\ \fR\fB\fIstyle\fR\fR] [\fB\-S\ \fR\fB\fImode\fR\fR] [\fB\-t\ \fR\fB\fIdirectory\fR\fR] [\fB\-w\ \fR\fB\fIdirectory\fR\fR] [\fB\-D\fR] [\fB\-W\ \fR\fB\fImode\fR\fR] {zonename} {filename} +.HP 18 +\fBnamed\-compilezone\fR [\fB\-d\fR] [\fB\-j\fR] [\fB\-q\fR] [\fB\-v\fR] [\fB\-c\ \fR\fB\fIclass\fR\fR] [\fB\-C\ \fR\fB\fImode\fR\fR] [\fB\-f\ \fR\fB\fIformat\fR\fR] [\fB\-F\ \fR\fB\fIformat\fR\fR] [\fB\-i\ \fR\fB\fImode\fR\fR] [\fB\-k\ \fR\fB\fImode\fR\fR] [\fB\-m\ \fR\fB\fImode\fR\fR] [\fB\-n\ \fR\fB\fImode\fR\fR] [\fB\-o\ \fR\fB\fIfilename\fR\fR] [\fB\-s\ \fR\fB\fIstyle\fR\fR] [\fB\-t\ \fR\fB\fIdirectory\fR\fR] [\fB\-w\ \fR\fB\fIdirectory\fR\fR] [\fB\-D\fR] [\fB\-W\ \fR\fB\fImode\fR\fR] {zonename} {filename} +.SH "DESCRIPTION" +.PP +\fBnamed\-checkzone\fR +checks the syntax and integrity of a zone file. It performs the same checks as +\fBnamed\fR +does when loading a zone. This makes +\fBnamed\-checkzone\fR +useful for checking zone files before configuring them into a name server. +.PP +\fBnamed\-compilezone\fR +is similar to +\fBnamed\-checkzone\fR, but it always dumps the zone contents to a specified file in a specified format. Additionally, it applies stricter check levels by default, since the dump output will be used as an actual zone file loaded by +\fBnamed\fR. When manually specified otherwise, the check levels must at least be as strict as those specified in the +\fBnamed\fR +configuration file. +.SH "OPTIONS" +.PP +\-d +.RS 4 +Enable debugging. +.RE +.PP +\-h +.RS 4 +Print the usage summary and exit. +.RE +.PP +\-q +.RS 4 +Quiet mode \- exit code only. +.RE +.PP +\-v +.RS 4 +Print the version of the +\fBnamed\-checkzone\fR +program and exit. +.RE +.PP +\-j +.RS 4 +When loading the zone file read the journal if it exists. +.RE +.PP +\-c \fIclass\fR +.RS 4 +Specify the class of the zone. If not specified, "IN" is assumed. +.RE +.PP +\-i \fImode\fR +.RS 4 +Perform post\-load zone integrity checks. Possible modes are +\fB"full"\fR +(default), +\fB"full\-sibling"\fR, +\fB"local"\fR, +\fB"local\-sibling"\fR +and +\fB"none"\fR. +.sp +Mode +\fB"full"\fR +checks that MX records refer to A or AAAA record (both in\-zone and out\-of\-zone hostnames). Mode +\fB"local"\fR +only checks MX records which refer to in\-zone hostnames. +.sp +Mode +\fB"full"\fR +checks that SRV records refer to A or AAAA record (both in\-zone and out\-of\-zone hostnames). Mode +\fB"local"\fR +only checks SRV records which refer to in\-zone hostnames. +.sp +Mode +\fB"full"\fR +checks that delegation NS records refer to A or AAAA record (both in\-zone and out\-of\-zone hostnames). It also checks that glue address records in the zone match those advertised by the child. Mode +\fB"local"\fR +only checks NS records which refer to in\-zone hostnames or that some required glue exists, that is when the nameserver is in a child zone. +.sp +Mode +\fB"full\-sibling"\fR +and +\fB"local\-sibling"\fR +disable sibling glue checks but are otherwise the same as +\fB"full"\fR +and +\fB"local"\fR +respectively. +.sp +Mode +\fB"none"\fR +disables the checks. +.RE +.PP +\-f \fIformat\fR +.RS 4 +Specify the format of the zone file. Possible formats are +\fB"text"\fR +(default) and +\fB"raw"\fR. +.RE +.PP +\-F \fIformat\fR +.RS 4 +Specify the format of the output file specified. Possible formats are +\fB"text"\fR +(default) and +\fB"raw"\fR. For +\fBnamed\-checkzone\fR, this does not cause any effects unless it dumps the zone contents. +.RE +.PP +\-k \fImode\fR +.RS 4 +Perform +\fB"check\-names"\fR +checks with the specified failure mode. Possible modes are +\fB"fail"\fR +(default for +\fBnamed\-compilezone\fR), +\fB"warn"\fR +(default for +\fBnamed\-checkzone\fR) and +\fB"ignore"\fR. +.RE +.PP +\-m \fImode\fR +.RS 4 +Specify whether MX records should be checked to see if they are addresses. Possible modes are +\fB"fail"\fR, +\fB"warn"\fR +(default) and +\fB"ignore"\fR. +.RE +.PP +\-M \fImode\fR +.RS 4 +Check if a MX record refers to a CNAME. Possible modes are +\fB"fail"\fR, +\fB"warn"\fR +(default) and +\fB"ignore"\fR. +.RE +.PP +\-n \fImode\fR +.RS 4 +Specify whether NS records should be checked to see if they are addresses. Possible modes are +\fB"fail"\fR +(default for +\fBnamed\-compilezone\fR), +\fB"warn"\fR +(default for +\fBnamed\-checkzone\fR) and +\fB"ignore"\fR. +.RE +.PP +\-o \fIfilename\fR +.RS 4 +Write zone output to +\fIfilename\fR. If +\fIfilename\fR +is +\fI\-\fR +then write to standard out. This is mandatory for +\fBnamed\-compilezone\fR. +.RE +.PP +\-s \fIstyle\fR +.RS 4 +Specify the style of the dumped zone file. Possible styles are +\fB"full"\fR +(default) and +\fB"relative"\fR. The full format is most suitable for processing automatically by a separate script. On the other hand, the relative format is more human\-readable and is thus suitable for editing by hand. For +\fBnamed\-checkzone\fR +this does not cause any effects unless it dumps the zone contents. It also does not have any meaning if the output format is not text. +.RE +.PP +\-S \fImode\fR +.RS 4 +Check if a SRV record refers to a CNAME. Possible modes are +\fB"fail"\fR, +\fB"warn"\fR +(default) and +\fB"ignore"\fR. +.RE +.PP +\-t \fIdirectory\fR +.RS 4 +Chroot to +\fIdirectory\fR +so that include directives in the configuration file are processed as if run by a similarly chrooted named. +.RE +.PP +\-w \fIdirectory\fR +.RS 4 +chdir to +\fIdirectory\fR +so that relative filenames in master file $INCLUDE directives work. This is similar to the directory clause in +\fInamed.conf\fR. +.RE +.PP +\-D +.RS 4 +Dump zone file in canonical format. This is always enabled for +\fBnamed\-compilezone\fR. +.RE +.PP +\-W \fImode\fR +.RS 4 +Specify whether to check for non\-terminal wildcards. Non\-terminal wildcards are almost always the result of a failure to understand the wildcard matching algorithm (RFC 1034). Possible modes are +\fB"warn"\fR +(default) and +\fB"ignore"\fR. +.RE +.PP +zonename +.RS 4 +The domain name of the zone being checked. +.RE +.PP +filename +.RS 4 +The name of the zone file. +.RE +.SH "RETURN VALUES" +.PP +\fBnamed\-checkzone\fR +returns an exit status of 1 if errors were detected and 0 otherwise. +.SH "SEE ALSO" +.PP +\fBnamed\fR(8), +\fBnamed\-checkconf\fR(8), +RFC 1035, +BIND 9 Administrator Reference Manual. +.SH "AUTHOR" +.PP +Internet Systems Consortium +.SH "COPYRIGHT" +Copyright \(co 2004\-2007, 2009 Internet Systems Consortium, Inc. ("ISC") +.br +Copyright \(co 2000\-2002 Internet Software Consortium. +.br diff --git a/contrib/bind-9.5.2/bin/check/named-checkzone.c b/contrib/bind-9.5.2/bin/check/named-checkzone.c new file mode 100644 index 0000000000..6d509ab240 --- /dev/null +++ b/contrib/bind-9.5.2/bin/check/named-checkzone.c @@ -0,0 +1,455 @@ +/* + * Copyright (C) 2004-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 + * 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: named-checkzone.c,v 1.49.130.5 2009/05/29 02:18:32 marka Exp $ */ + +/*! \file */ + +#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 "check-tool.h" + +static int quiet = 0; +static isc_mem_t *mctx = NULL; +static isc_entropy_t *ectx = NULL; +dns_zone_t *zone = NULL; +dns_zonetype_t zonetype = dns_zone_master; +static int dumpzone = 0; +static const char *output_filename; +static char *prog_name = NULL; +static const dns_master_style_t *outputstyle = NULL; +static enum { progmode_check, progmode_compile } progmode; + +#define ERRRET(result, function) \ + do { \ + if (result != ISC_R_SUCCESS) { \ + if (!quiet) \ + fprintf(stderr, "%s() returned %s\n", \ + function, dns_result_totext(result)); \ + return (result); \ + } \ + } while (0) + +static void +usage(void) { + fprintf(stderr, + "usage: %s [-djqvD] [-c class] [-o output] " + "[-f inputformat] [-F outputformat] " + "[-t directory] [-w directory] [-k (ignore|warn|fail)] " + "[-n (ignore|warn|fail)] [-m (ignore|warn|fail)] " + "[-i (full|full-sibling|local|local-sibling|none)] " + "[-M (ignore|warn|fail)] [-S (ignore|warn|fail)] " + "[-W (ignore|warn)] " + "zonename filename\n", prog_name); + exit(1); +} + +static void +destroy(void) { + if (zone != NULL) + dns_zone_detach(&zone); + dns_name_destroy(); +} + +/*% main processing routine */ +int +main(int argc, char **argv) { + int c; + char *origin = NULL; + char *filename = NULL; + isc_log_t *lctx = NULL; + isc_result_t result; + char classname_in[] = "IN"; + char *classname = classname_in; + const char *workdir = NULL; + const char *inputformatstr = NULL; + const char *outputformatstr = NULL; + dns_masterformat_t inputformat = dns_masterformat_text; + dns_masterformat_t outputformat = dns_masterformat_text; + FILE *errout = stdout; + + outputstyle = &dns_master_style_full; + + prog_name = strrchr(argv[0], '/'); + if (prog_name == NULL) + prog_name = strrchr(argv[0], '\\'); + if (prog_name != NULL) + prog_name++; + else + prog_name = argv[0]; + /* + * Libtool doesn't preserve the program name prior to final + * installation. Remove the libtool prefix ("lt-"). + */ + if (strncmp(prog_name, "lt-", 3) == 0) + prog_name += 3; + +#define PROGCMP(X) \ + (strcasecmp(prog_name, X) == 0 || strcasecmp(prog_name, X ".exe") == 0) + + if (PROGCMP("named-checkzone")) + progmode = progmode_check; + else if (PROGCMP("named-compilezone")) + progmode = progmode_compile; + else + INSIST(0); + + /* Compilation specific defaults */ + if (progmode == progmode_compile) { + zone_options |= (DNS_ZONEOPT_CHECKNS | + DNS_ZONEOPT_FATALNS | + DNS_ZONEOPT_CHECKNAMES | + DNS_ZONEOPT_CHECKNAMESFAIL | + DNS_ZONEOPT_CHECKWILDCARD); + } + +#define ARGCMP(X) (strcmp(isc_commandline_argument, X) == 0) + + isc_commandline_errprint = ISC_FALSE; + + while ((c = isc_commandline_parse(argc, argv, + "c:df:hi:jk:m:n:qs:t:o:vw:DF:M:S:W:")) + != EOF) { + switch (c) { + case 'c': + classname = isc_commandline_argument; + break; + + case 'd': + debug++; + break; + + case 'i': + if (ARGCMP("full")) { + zone_options |= DNS_ZONEOPT_CHECKINTEGRITY | + DNS_ZONEOPT_CHECKSIBLING; + docheckmx = ISC_TRUE; + docheckns = ISC_TRUE; + dochecksrv = ISC_TRUE; + } else if (ARGCMP("full-sibling")) { + zone_options |= DNS_ZONEOPT_CHECKINTEGRITY; + zone_options &= ~DNS_ZONEOPT_CHECKSIBLING; + docheckmx = ISC_TRUE; + docheckns = ISC_TRUE; + dochecksrv = ISC_TRUE; + } else if (ARGCMP("local")) { + zone_options |= DNS_ZONEOPT_CHECKINTEGRITY; + zone_options |= DNS_ZONEOPT_CHECKSIBLING; + docheckmx = ISC_FALSE; + docheckns = ISC_FALSE; + dochecksrv = ISC_FALSE; + } else if (ARGCMP("local-sibling")) { + zone_options |= DNS_ZONEOPT_CHECKINTEGRITY; + zone_options &= ~DNS_ZONEOPT_CHECKSIBLING; + docheckmx = ISC_FALSE; + docheckns = ISC_FALSE; + dochecksrv = ISC_FALSE; + } else if (ARGCMP("none")) { + zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY; + zone_options &= ~DNS_ZONEOPT_CHECKSIBLING; + docheckmx = ISC_FALSE; + docheckns = ISC_FALSE; + dochecksrv = ISC_FALSE; + } else { + fprintf(stderr, "invalid argument to -i: %s\n", + isc_commandline_argument); + exit(1); + } + break; + + case 'f': + inputformatstr = isc_commandline_argument; + break; + + case 'F': + outputformatstr = isc_commandline_argument; + break; + + case 'j': + nomerge = ISC_FALSE; + break; + + case 'k': + if (ARGCMP("warn")) { + zone_options |= DNS_ZONEOPT_CHECKNAMES; + zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL; + } else if (ARGCMP("fail")) { + zone_options |= DNS_ZONEOPT_CHECKNAMES | + DNS_ZONEOPT_CHECKNAMESFAIL; + } else if (ARGCMP("ignore")) { + zone_options &= ~(DNS_ZONEOPT_CHECKNAMES | + DNS_ZONEOPT_CHECKNAMESFAIL); + } else { + fprintf(stderr, "invalid argument to -k: %s\n", + isc_commandline_argument); + exit(1); + } + break; + + case 'n': + if (ARGCMP("ignore")) { + zone_options &= ~(DNS_ZONEOPT_CHECKNS| + DNS_ZONEOPT_FATALNS); + } else if (ARGCMP("warn")) { + zone_options |= DNS_ZONEOPT_CHECKNS; + zone_options &= ~DNS_ZONEOPT_FATALNS; + } else if (ARGCMP("fail")) { + zone_options |= DNS_ZONEOPT_CHECKNS| + DNS_ZONEOPT_FATALNS; + } else { + fprintf(stderr, "invalid argument to -n: %s\n", + isc_commandline_argument); + exit(1); + } + break; + + case 'm': + if (ARGCMP("warn")) { + zone_options |= DNS_ZONEOPT_CHECKMX; + zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL; + } else if (ARGCMP("fail")) { + zone_options |= DNS_ZONEOPT_CHECKMX | + DNS_ZONEOPT_CHECKMXFAIL; + } else if (ARGCMP("ignore")) { + zone_options &= ~(DNS_ZONEOPT_CHECKMX | + DNS_ZONEOPT_CHECKMXFAIL); + } else { + fprintf(stderr, "invalid argument to -m: %s\n", + isc_commandline_argument); + exit(1); + } + break; + + case 'q': + quiet++; + break; + + case 't': + result = isc_dir_chroot(isc_commandline_argument); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "isc_dir_chroot: %s: %s\n", + isc_commandline_argument, + isc_result_totext(result)); + exit(1); + } + break; + + case 's': + if (ARGCMP("full")) + outputstyle = &dns_master_style_full; + else if (ARGCMP("relative")) { + outputstyle = &dns_master_style_default; + } else { + fprintf(stderr, + "unknown or unsupported style: %s\n", + isc_commandline_argument); + exit(1); + } + break; + + case 'o': + output_filename = isc_commandline_argument; + break; + + case 'v': + printf(VERSION "\n"); + exit(0); + + case 'w': + workdir = isc_commandline_argument; + break; + + case 'D': + dumpzone++; + break; + + case 'M': + if (ARGCMP("fail")) { + zone_options &= ~DNS_ZONEOPT_WARNMXCNAME; + zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME; + } else if (ARGCMP("warn")) { + zone_options |= DNS_ZONEOPT_WARNMXCNAME; + zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME; + } else if (ARGCMP("ignore")) { + zone_options |= DNS_ZONEOPT_WARNMXCNAME; + zone_options |= DNS_ZONEOPT_IGNOREMXCNAME; + } else { + fprintf(stderr, "invalid argument to -M: %s\n", + isc_commandline_argument); + exit(1); + } + break; + + case 'S': + if (ARGCMP("fail")) { + zone_options &= ~DNS_ZONEOPT_WARNSRVCNAME; + zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME; + } else if (ARGCMP("warn")) { + zone_options |= DNS_ZONEOPT_WARNSRVCNAME; + zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME; + } else if (ARGCMP("ignore")) { + zone_options |= DNS_ZONEOPT_WARNSRVCNAME; + zone_options |= DNS_ZONEOPT_IGNORESRVCNAME; + } else { + fprintf(stderr, "invalid argument to -S: %s\n", + isc_commandline_argument); + exit(1); + } + break; + + case 'W': + if (ARGCMP("warn")) + zone_options |= DNS_ZONEOPT_CHECKWILDCARD; + else if (ARGCMP("ignore")) + zone_options &= ~DNS_ZONEOPT_CHECKWILDCARD; + break; + + case '?': + if (isc_commandline_option != '?') + fprintf(stderr, "%s: invalid argument -%c\n", + prog_name, isc_commandline_option); + case 'h': + usage(); + + default: + fprintf(stderr, "%s: unhandled option -%c\n", + prog_name, isc_commandline_option); + exit(1); + } + } + + if (workdir != NULL) { + result = isc_dir_chdir(workdir); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "isc_dir_chdir: %s: %s\n", + workdir, isc_result_totext(result)); + exit(1); + } + } + + if (inputformatstr != NULL) { + if (strcasecmp(inputformatstr, "text") == 0) + inputformat = dns_masterformat_text; + else if (strcasecmp(inputformatstr, "raw") == 0) + inputformat = dns_masterformat_raw; + else { + fprintf(stderr, "unknown file format: %s\n", + inputformatstr); + exit(1); + } + } + + if (outputformatstr != NULL) { + if (strcasecmp(outputformatstr, "text") == 0) + outputformat = dns_masterformat_text; + else if (strcasecmp(outputformatstr, "raw") == 0) + outputformat = dns_masterformat_raw; + else { + fprintf(stderr, "unknown file format: %s\n", + outputformatstr); + exit(1); + } + } + + if (progmode == progmode_compile) { + dumpzone = 1; /* always dump */ + if (output_filename == NULL) { + fprintf(stderr, + "output file required, but not specified\n"); + usage(); + } + } + + if (output_filename != NULL) + dumpzone = 1; + + /* + * If we are outputing to stdout then send the informational + * output to stderr. + */ + if (dumpzone && + (output_filename == NULL || + strcmp(output_filename, "-") == 0 || + strcmp(output_filename, "/dev/fd/1") == 0 || + strcmp(output_filename, "/dev/stdout") == 0)) + errout = stderr; + + if (isc_commandline_index + 2 != argc) + usage(); + + RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS); + if (!quiet) + RUNTIME_CHECK(setup_logging(mctx, errout, &lctx) + == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_entropy_create(mctx, &ectx) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE) + == ISC_R_SUCCESS); + + dns_result_register(); + + origin = argv[isc_commandline_index++]; + filename = argv[isc_commandline_index++]; + result = load_zone(mctx, origin, filename, inputformat, classname, + &zone); + + if (result == ISC_R_SUCCESS && dumpzone) { + if (!quiet && progmode == progmode_compile) { + fprintf(errout, "dump zone to %s...", output_filename); + fflush(errout); + } + result = dump_zone(origin, zone, output_filename, + outputformat, outputstyle); + if (!quiet && progmode == progmode_compile) + fprintf(errout, "done\n"); + } + + if (!quiet && result == ISC_R_SUCCESS) + fprintf(errout, "OK\n"); + destroy(); + if (lctx != NULL) + isc_log_destroy(&lctx); + isc_hash_destroy(); + isc_entropy_detach(&ectx); + isc_mem_destroy(&mctx); + return ((result == ISC_R_SUCCESS) ? 0 : 1); +} diff --git a/contrib/bind-9.5.2/bin/check/named-checkzone.html b/contrib/bind-9.5.2/bin/check/named-checkzone.html new file mode 100644 index 0000000000..ae11598bbc --- /dev/null +++ b/contrib/bind-9.5.2/bin/check/named-checkzone.html @@ -0,0 +1,262 @@ + + + + + +named-checkzone + + +
+
+
+

Name

+

named-checkzone, named-compilezone — zone file validity checking or converting tool

+
+
+

Synopsis

+

named-checkzone [-d] [-h] [-j] [-q] [-v] [-c class] [-f format] [-F format] [-i mode] [-k mode] [-m mode] [-M mode] [-n mode] [-o filename] [-s style] [-S mode] [-t directory] [-w directory] [-D] [-W mode] {zonename} {filename}

+

named-compilezone [-d] [-j] [-q] [-v] [-c class] [-C mode] [-f format] [-F format] [-i mode] [-k mode] [-m mode] [-n mode] [-o filename] [-s style] [-t directory] [-w directory] [-D] [-W mode] {zonename} {filename}

+
+
+

DESCRIPTION

+

named-checkzone + checks the syntax and integrity of a zone file. It performs the + same checks as named does when loading a + zone. This makes named-checkzone useful for + checking zone files before configuring them into a name server. +

+

+ named-compilezone is similar to + named-checkzone, but it always dumps the + zone contents to a specified file in a specified format. + Additionally, it applies stricter check levels by default, + since the dump output will be used as an actual zone file + loaded by named. + When manually specified otherwise, the check levels must at + least be as strict as those specified in the + named configuration file. +

+
+
+

OPTIONS

+
+
-d
+

+ Enable debugging. +

+
-h
+

+ Print the usage summary and exit. +

+
-q
+

+ Quiet mode - exit code only. +

+
-v
+

+ Print the version of the named-checkzone + program and exit. +

+
-j
+

+ When loading the zone file read the journal if it exists. +

+
-c class
+

+ Specify the class of the zone. If not specified, "IN" is assumed. +

+
-i mode
+
+

+ Perform post-load zone integrity checks. Possible modes are + "full" (default), + "full-sibling", + "local", + "local-sibling" and + "none". +

+

+ Mode "full" checks that MX records + refer to A or AAAA record (both in-zone and out-of-zone + hostnames). Mode "local" only + checks MX records which refer to in-zone hostnames. +

+

+ Mode "full" checks that SRV records + refer to A or AAAA record (both in-zone and out-of-zone + hostnames). Mode "local" only + checks SRV records which refer to in-zone hostnames. +

+

+ Mode "full" checks that delegation NS + records refer to A or AAAA record (both in-zone and out-of-zone + hostnames). It also checks that glue address records + in the zone match those advertised by the child. + Mode "local" only checks NS records which + refer to in-zone hostnames or that some required glue exists, + that is when the nameserver is in a child zone. +

+

+ Mode "full-sibling" and + "local-sibling" disable sibling glue + checks but are otherwise the same as "full" + and "local" respectively. +

+

+ Mode "none" disables the checks. +

+
+
-f format
+

+ Specify the format of the zone file. + Possible formats are "text" (default) + and "raw". +

+
-F format
+

+ Specify the format of the output file specified. + Possible formats are "text" (default) + and "raw". + For named-checkzone, + this does not cause any effects unless it dumps the zone + contents. +

+
-k mode
+

+ Perform "check-names" checks with the + specified failure mode. + Possible modes are "fail" + (default for named-compilezone), + "warn" + (default for named-checkzone) and + "ignore". +

+
-m mode
+

+ Specify whether MX records should be checked to see if they + are addresses. Possible modes are "fail", + "warn" (default) and + "ignore". +

+
-M mode
+

+ Check if a MX record refers to a CNAME. + Possible modes are "fail", + "warn" (default) and + "ignore". +

+
-n mode
+

+ Specify whether NS records should be checked to see if they + are addresses. + Possible modes are "fail" + (default for named-compilezone), + "warn" + (default for named-checkzone) and + "ignore". +

+
-o filename
+

+ Write zone output to filename. + If filename is - then + write to standard out. + This is mandatory for named-compilezone. +

+
-s style
+

+ Specify the style of the dumped zone file. + Possible styles are "full" (default) + and "relative". + The full format is most suitable for processing + automatically by a separate script. + On the other hand, the relative format is more + human-readable and is thus suitable for editing by hand. + For named-checkzone + this does not cause any effects unless it dumps the zone + contents. + It also does not have any meaning if the output format + is not text. +

+
-S mode
+

+ Check if a SRV record refers to a CNAME. + Possible modes are "fail", + "warn" (default) and + "ignore". +

+
-t directory
+

+ Chroot to directory so that + include + directives in the configuration file are processed as if + run by a similarly chrooted named. +

+
-w directory
+

+ chdir to directory so that + relative + filenames in master file $INCLUDE directives work. This + is similar to the directory clause in + named.conf. +

+
-D
+

+ Dump zone file in canonical format. + This is always enabled for named-compilezone. +

+
-W mode
+

+ Specify whether to check for non-terminal wildcards. + Non-terminal wildcards are almost always the result of a + failure to understand the wildcard matching algorithm (RFC 1034). + Possible modes are "warn" (default) + and + "ignore". +

+
zonename
+

+ The domain name of the zone being checked. +

+
filename
+

+ The name of the zone file. +

+
+
+
+

RETURN VALUES

+

named-checkzone + returns an exit status of 1 if + errors were detected and 0 otherwise. +

+
+
+

SEE ALSO

+

named(8), + named-checkconf(8), + RFC 1035, + BIND 9 Administrator Reference Manual. +

+
+
+

AUTHOR

+

Internet Systems Consortium +

+
+
+ diff --git a/contrib/bind-9.5.2/bin/dig/dig.1 b/contrib/bind-9.5.2/bin/dig/dig.1 new file mode 100644 index 0000000000..3a63d433bf --- /dev/null +++ b/contrib/bind-9.5.2/bin/dig/dig.1 @@ -0,0 +1,568 @@ +.\" 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 +.\" 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: dig.1,v 1.45.150.8 2009/07/11 01:43:26 tbox Exp $ +.\" +.hy 0 +.ad l +.\" Title: dig +.\" Author: +.\" Generator: DocBook XSL Stylesheets v1.71.1 +.\" Date: Jun 30, 2000 +.\" Manual: BIND9 +.\" Source: BIND9 +.\" +.TH "DIG" "1" "Jun 30, 2000" "BIND9" "BIND9" +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.SH "NAME" +dig \- DNS lookup utility +.SH "SYNOPSIS" +.HP 4 +\fBdig\fR [@server] [\fB\-b\ \fR\fB\fIaddress\fR\fR] [\fB\-c\ \fR\fB\fIclass\fR\fR] [\fB\-f\ \fR\fB\fIfilename\fR\fR] [\fB\-k\ \fR\fB\fIfilename\fR\fR] [\fB\-m\fR] [\fB\-p\ \fR\fB\fIport#\fR\fR] [\fB\-q\ \fR\fB\fIname\fR\fR] [\fB\-t\ \fR\fB\fItype\fR\fR] [\fB\-x\ \fR\fB\fIaddr\fR\fR] [\fB\-y\ \fR\fB\fI[hmac:]\fR\fIname:key\fR\fR] [\fB\-4\fR] [\fB\-6\fR] [name] [type] [class] [queryopt...] +.HP 4 +\fBdig\fR [\fB\-h\fR] +.HP 4 +\fBdig\fR [global\-queryopt...] [query...] +.SH "DESCRIPTION" +.PP +\fBdig\fR +(domain information groper) is a flexible tool for interrogating DNS name servers. It performs DNS lookups and displays the answers that are returned from the name server(s) that were queried. Most DNS administrators use +\fBdig\fR +to troubleshoot DNS problems because of its flexibility, ease of use and clarity of output. Other lookup tools tend to have less functionality than +\fBdig\fR. +.PP +Although +\fBdig\fR +is normally used with command\-line arguments, it also has a batch mode of operation for reading lookup requests from a file. A brief summary of its command\-line arguments and options is printed when the +\fB\-h\fR +option is given. Unlike earlier versions, the BIND 9 implementation of +\fBdig\fR +allows multiple lookups to be issued from the command line. +.PP +Unless it is told to query a specific name server, +\fBdig\fR +will try each of the servers listed in +\fI/etc/resolv.conf\fR. +.PP +When no command line arguments or options are given, +\fBdig\fR +will perform an NS query for "." (the root). +.PP +It is possible to set per\-user defaults for +\fBdig\fR +via +\fI${HOME}/.digrc\fR. This file is read and any options in it are applied before the command line arguments. +.PP +The IN and CH class names overlap with the IN and CH top level domains names. Either use the +\fB\-t\fR +and +\fB\-c\fR +options to specify the type and class, use the +\fB\-q\fR +the specify the domain name, or use "IN." and "CH." when looking up these top level domains. +.SH "SIMPLE USAGE" +.PP +A typical invocation of +\fBdig\fR +looks like: +.sp +.RS 4 +.nf + dig @server name type +.fi +.RE +.sp +where: +.PP +\fBserver\fR +.RS 4 +is the name or IP address of the name server to query. This can be an IPv4 address in dotted\-decimal notation or an IPv6 address in colon\-delimited notation. When the supplied +\fIserver\fR +argument is a hostname, +\fBdig\fR +resolves that name before querying that name server. If no +\fIserver\fR +argument is provided, +\fBdig\fR +consults +\fI/etc/resolv.conf\fR +and queries the name servers listed there. The reply from the name server that responds is displayed. +.RE +.PP +\fBname\fR +.RS 4 +is the name of the resource record that is to be looked up. +.RE +.PP +\fBtype\fR +.RS 4 +indicates what type of query is required \(em ANY, A, MX, SIG, etc. +\fItype\fR +can be any valid query type. If no +\fItype\fR +argument is supplied, +\fBdig\fR +will perform a lookup for an A record. +.RE +.SH "OPTIONS" +.PP +The +\fB\-b\fR +option sets the source IP address of the query to +\fIaddress\fR. This must be a valid address on one of the host's network interfaces or "0.0.0.0" or "::". An optional port may be specified by appending "#" +.PP +The default query class (IN for internet) is overridden by the +\fB\-c\fR +option. +\fIclass\fR +is any valid class, such as HS for Hesiod records or CH for Chaosnet records. +.PP +The +\fB\-f\fR +option makes +\fBdig \fR +operate in batch mode by reading a list of lookup requests to process from the file +\fIfilename\fR. The file contains a number of queries, one per line. Each entry in the file should be organized in the same way they would be presented as queries to +\fBdig\fR +using the command\-line interface. +.PP +The +\fB\-m\fR +option enables memory usage debugging. +.PP +If a non\-standard port number is to be queried, the +\fB\-p\fR +option is used. +\fIport#\fR +is the port number that +\fBdig\fR +will send its queries instead of the standard DNS port number 53. This option would be used to test a name server that has been configured to listen for queries on a non\-standard port number. +.PP +The +\fB\-4\fR +option forces +\fBdig\fR +to only use IPv4 query transport. The +\fB\-6\fR +option forces +\fBdig\fR +to only use IPv6 query transport. +.PP +The +\fB\-t\fR +option sets the query type to +\fItype\fR. It can be any valid query type which is supported in BIND 9. The default query type is "A", unless the +\fB\-x\fR +option is supplied to indicate a reverse lookup. A zone transfer can be requested by specifying a type of AXFR. When an incremental zone transfer (IXFR) is required, +\fItype\fR +is set to +ixfr=N. The incremental zone transfer will contain the changes made to the zone since the serial number in the zone's SOA record was +\fIN\fR. +.PP +The +\fB\-q\fR +option sets the query name to +\fIname\fR. This useful do distinguish the +\fIname\fR +from other arguments. +.PP +Reverse lookups \(em mapping addresses to names \(em are simplified by the +\fB\-x\fR +option. +\fIaddr\fR +is an IPv4 address in dotted\-decimal notation, or a colon\-delimited IPv6 address. When this option is used, there is no need to provide the +\fIname\fR, +\fIclass\fR +and +\fItype\fR +arguments. +\fBdig\fR +automatically performs a lookup for a name like +11.12.13.10.in\-addr.arpa +and sets the query type and class to PTR and IN respectively. By default, IPv6 addresses are looked up using nibble format under the IP6.ARPA domain. To use the older RFC1886 method using the IP6.INT domain specify the +\fB\-i\fR +option. Bit string labels (RFC2874) are now experimental and are not attempted. +.PP +To sign the DNS queries sent by +\fBdig\fR +and their responses using transaction signatures (TSIG), specify a TSIG key file using the +\fB\-k\fR +option. You can also specify the TSIG key itself on the command line using the +\fB\-y\fR +option; +\fIhmac\fR +is the type of the TSIG, default HMAC\-MD5, +\fIname\fR +is the name of the TSIG key and +\fIkey\fR +is the actual key. The key is a base\-64 encoded string, typically generated by +\fBdnssec\-keygen\fR(8). Caution should be taken when using the +\fB\-y\fR +option on multi\-user systems as the key can be visible in the output from +\fBps\fR(1) +or in the shell's history file. When using TSIG authentication with +\fBdig\fR, the name server that is queried needs to know the key and algorithm that is being used. In BIND, this is done by providing appropriate +\fBkey\fR +and +\fBserver\fR +statements in +\fInamed.conf\fR. +.SH "QUERY OPTIONS" +.PP +\fBdig\fR +provides a number of query options which affect the way in which lookups are made and the results displayed. Some of these set or reset flag bits in the query header, some determine which sections of the answer get printed, and others determine the timeout and retry strategies. +.PP +Each query option is identified by a keyword preceded by a plus sign (+). Some keywords set or reset an option. These may be preceded by the string +no +to negate the meaning of that keyword. Other keywords assign values to options like the timeout interval. They have the form +\fB+keyword=value\fR. The query options are: +.PP +\fB+[no]tcp\fR +.RS 4 +Use [do not use] TCP when querying name servers. The default behavior is to use UDP unless an AXFR or IXFR query is requested, in which case a TCP connection is used. +.RE +.PP +\fB+[no]vc\fR +.RS 4 +Use [do not use] TCP when querying name servers. This alternate syntax to +\fI+[no]tcp\fR +is provided for backwards compatibility. The "vc" stands for "virtual circuit". +.RE +.PP +\fB+[no]ignore\fR +.RS 4 +Ignore truncation in UDP responses instead of retrying with TCP. By default, TCP retries are performed. +.RE +.PP +\fB+domain=somename\fR +.RS 4 +Set the search list to contain the single domain +\fIsomename\fR, as if specified in a +\fBdomain\fR +directive in +\fI/etc/resolv.conf\fR, and enable search list processing as if the +\fI+search\fR +option were given. +.RE +.PP +\fB+[no]search\fR +.RS 4 +Use [do not use] the search list defined by the searchlist or domain directive in +\fIresolv.conf\fR +(if any). The search list is not used by default. +.RE +.PP +\fB+[no]showsearch\fR +.RS 4 +Perform [do not perform] a search showing intermediate results. +.RE +.PP +\fB+[no]defname\fR +.RS 4 +Deprecated, treated as a synonym for +\fI+[no]search\fR +.RE +.PP +\fB+[no]aaonly\fR +.RS 4 +Sets the "aa" flag in the query. +.RE +.PP +\fB+[no]aaflag\fR +.RS 4 +A synonym for +\fI+[no]aaonly\fR. +.RE +.PP +\fB+[no]adflag\fR +.RS 4 +Set [do not set] the AD (authentic data) bit in the query. This requests the server to return whether all of the answer and authority sections have all been validated as secure according to the security policy of the server. AD=1 indicates that all records have been validated as secure and the answer is not from a OPT\-OUT range. AD=0 indicate that some part of the answer was insecure or not validated. +.RE +.PP +\fB+[no]cdflag\fR +.RS 4 +Set [do not set] the CD (checking disabled) bit in the query. This requests the server to not perform DNSSEC validation of responses. +.RE +.PP +\fB+[no]cl\fR +.RS 4 +Display [do not display] the CLASS when printing the record. +.RE +.PP +\fB+[no]ttlid\fR +.RS 4 +Display [do not display] the TTL when printing the record. +.RE +.PP +\fB+[no]recurse\fR +.RS 4 +Toggle the setting of the RD (recursion desired) bit in the query. This bit is set by default, which means +\fBdig\fR +normally sends recursive queries. Recursion is automatically disabled when the +\fI+nssearch\fR +or +\fI+trace\fR +query options are used. +.RE +.PP +\fB+[no]nssearch\fR +.RS 4 +When this option is set, +\fBdig\fR +attempts to find the authoritative name servers for the zone containing the name being looked up and display the SOA record that each name server has for the zone. +.RE +.PP +\fB+[no]trace\fR +.RS 4 +Toggle tracing of the delegation path from the root name servers for the name being looked up. Tracing is disabled by default. When tracing is enabled, +\fBdig\fR +makes iterative queries to resolve the name being looked up. It will follow referrals from the root servers, showing the answer from each server that was used to resolve the lookup. +.RE +.PP +\fB+[no]cmd\fR +.RS 4 +Toggles the printing of the initial comment in the output identifying the version of +\fBdig\fR +and the query options that have been applied. This comment is printed by default. +.RE +.PP +\fB+[no]short\fR +.RS 4 +Provide a terse answer. The default is to print the answer in a verbose form. +.RE +.PP +\fB+[no]identify\fR +.RS 4 +Show [or do not show] the IP address and port number that supplied the answer when the +\fI+short\fR +option is enabled. If short form answers are requested, the default is not to show the source address and port number of the server that provided the answer. +.RE +.PP +\fB+[no]comments\fR +.RS 4 +Toggle the display of comment lines in the output. The default is to print comments. +.RE +.PP +\fB+[no]stats\fR +.RS 4 +This query option toggles the printing of statistics: when the query was made, the size of the reply and so on. The default behavior is to print the query statistics. +.RE +.PP +\fB+[no]qr\fR +.RS 4 +Print [do not print] the query as it is sent. By default, the query is not printed. +.RE +.PP +\fB+[no]question\fR +.RS 4 +Print [do not print] the question section of a query when an answer is returned. The default is to print the question section as a comment. +.RE +.PP +\fB+[no]answer\fR +.RS 4 +Display [do not display] the answer section of a reply. The default is to display it. +.RE +.PP +\fB+[no]authority\fR +.RS 4 +Display [do not display] the authority section of a reply. The default is to display it. +.RE +.PP +\fB+[no]additional\fR +.RS 4 +Display [do not display] the additional section of a reply. The default is to display it. +.RE +.PP +\fB+[no]all\fR +.RS 4 +Set or clear all display flags. +.RE +.PP +\fB+time=T\fR +.RS 4 +Sets the timeout for a query to +\fIT\fR +seconds. The default timeout is 5 seconds. An attempt to set +\fIT\fR +to less than 1 will result in a query timeout of 1 second being applied. +.RE +.PP +\fB+tries=T\fR +.RS 4 +Sets the number of times to try UDP queries to server to +\fIT\fR +instead of the default, 3. If +\fIT\fR +is less than or equal to zero, the number of tries is silently rounded up to 1. +.RE +.PP +\fB+retry=T\fR +.RS 4 +Sets the number of times to retry UDP queries to server to +\fIT\fR +instead of the default, 2. Unlike +\fI+tries\fR, this does not include the initial query. +.RE +.PP +\fB+ndots=D\fR +.RS 4 +Set the number of dots that have to appear in +\fIname\fR +to +\fID\fR +for it to be considered absolute. The default value is that defined using the ndots statement in +\fI/etc/resolv.conf\fR, or 1 if no ndots statement is present. Names with fewer dots are interpreted as relative names and will be searched for in the domains listed in the +\fBsearch\fR +or +\fBdomain\fR +directive in +\fI/etc/resolv.conf\fR. +.RE +.PP +\fB+bufsize=B\fR +.RS 4 +Set the UDP message buffer size advertised using EDNS0 to +\fIB\fR +bytes. The maximum and minimum sizes of this buffer are 65535 and 0 respectively. Values outside this range are rounded up or down appropriately. Values other than zero will cause a EDNS query to be sent. +.RE +.PP +\fB+edns=#\fR +.RS 4 +Specify the EDNS version to query with. Valid values are 0 to 255. Setting the EDNS version will cause a EDNS query to be sent. +\fB+noedns\fR +clears the remembered EDNS version. +.RE +.PP +\fB+[no]multiline\fR +.RS 4 +Print records like the SOA records in a verbose multi\-line format with human\-readable comments. The default is to print each record on a single line, to facilitate machine parsing of the +\fBdig\fR +output. +.RE +.PP +\fB+[no]fail\fR +.RS 4 +Do not try the next server if you receive a SERVFAIL. The default is to not try the next server which is the reverse of normal stub resolver behavior. +.RE +.PP +\fB+[no]besteffort\fR +.RS 4 +Attempt to display the contents of messages which are malformed. The default is to not display malformed answers. +.RE +.PP +\fB+[no]dnssec\fR +.RS 4 +Requests DNSSEC records be sent by setting the DNSSEC OK bit (DO) in the OPT record in the additional section of the query. +.RE +.PP +\fB+[no]sigchase\fR +.RS 4 +Chase DNSSEC signature chains. Requires dig be compiled with \-DDIG_SIGCHASE. +.RE +.PP +\fB+trusted\-key=####\fR +.RS 4 +Specifies a file containing trusted keys to be used with +\fB+sigchase\fR. Each DNSKEY record must be on its own line. +.sp +If not specified, +\fBdig\fR +will look for +\fI/etc/trusted\-key.key\fR +then +\fItrusted\-key.key\fR +in the current directory. +.sp +Requires dig be compiled with \-DDIG_SIGCHASE. +.RE +.PP +\fB+[no]topdown\fR +.RS 4 +When chasing DNSSEC signature chains perform a top\-down validation. Requires dig be compiled with \-DDIG_SIGCHASE. +.RE +.PP +\fB+[no]nsid\fR +.RS 4 +Include an EDNS name server ID request when sending a query. +.RE +.SH "MULTIPLE QUERIES" +.PP +The BIND 9 implementation of +\fBdig \fR +supports specifying multiple queries on the command line (in addition to supporting the +\fB\-f\fR +batch file option). Each of those queries can be supplied with its own set of flags, options and query options. +.PP +In this case, each +\fIquery\fR +argument represent an individual query in the command\-line syntax described above. Each consists of any of the standard options and flags, the name to be looked up, an optional query type and class and any query options that should be applied to that query. +.PP +A global set of query options, which should be applied to all queries, can also be supplied. These global query options must precede the first tuple of name, class, type, options, flags, and query options supplied on the command line. Any global query options (except the +\fB+[no]cmd\fR +option) can be overridden by a query\-specific set of query options. For example: +.sp +.RS 4 +.nf +dig +qr www.isc.org any \-x 127.0.0.1 isc.org ns +noqr +.fi +.RE +.sp +shows how +\fBdig\fR +could be used from the command line to make three lookups: an ANY query for +www.isc.org, a reverse lookup of 127.0.0.1 and a query for the NS records of +isc.org. A global query option of +\fI+qr\fR +is applied, so that +\fBdig\fR +shows the initial query it made for each lookup. The final query has a local query option of +\fI+noqr\fR +which means that +\fBdig\fR +will not print the initial query when it looks up the NS records for +isc.org. +.SH "IDN SUPPORT" +.PP +If +\fBdig\fR +has been built with IDN (internationalized domain name) support, it can accept and display non\-ASCII domain names. +\fBdig\fR +appropriately converts character encoding of domain name before sending a request to DNS server or displaying a reply from the server. If you'd like to turn off the IDN support for some reason, defines the +\fBIDN_DISABLE\fR +environment variable. The IDN support is disabled if the variable is set when +\fBdig\fR +runs. +.SH "FILES" +.PP +\fI/etc/resolv.conf\fR +.PP +\fI${HOME}/.digrc\fR +.SH "SEE ALSO" +.PP +\fBhost\fR(1), +\fBnamed\fR(8), +\fBdnssec\-keygen\fR(8), +RFC1035. +.SH "BUGS" +.PP +There are probably too many query options. +.SH "COPYRIGHT" +Copyright \(co 2004\-2009 Internet Systems Consortium, Inc. ("ISC") +.br +Copyright \(co 2000\-2003 Internet Software Consortium. +.br diff --git a/contrib/bind-9.5.2/bin/dig/dig.c b/contrib/bind-9.5.2/bin/dig/dig.c new file mode 100644 index 0000000000..e511d9066f --- /dev/null +++ b/contrib/bind-9.5.2/bin/dig/dig.c @@ -0,0 +1,1839 @@ +/* + * 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 + * 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: dig.c,v 1.218.12.9 2009/05/06 10:19:49 fdupont Exp $ */ + +/*! \file */ + +#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 ADD_STRING(b, s) { \ + if (strlen(s) >= isc_buffer_availablelength(b)) \ + return (ISC_R_NOSPACE); \ + else \ + isc_buffer_putstr(b, s); \ +} + +#define DIG_MAX_ADDRESSES 20 + +dig_lookup_t *default_lookup = NULL; + +static char *batchname = NULL; +static FILE *batchfp = NULL; +static char *argv0; +static int addresscount = 0; + +static char domainopt[DNS_NAME_MAXTEXT]; + +static isc_boolean_t short_form = ISC_FALSE, printcmd = ISC_TRUE, + ip6_int = ISC_FALSE, plusquest = ISC_FALSE, pluscomm = ISC_FALSE, + multiline = ISC_FALSE, nottl = ISC_FALSE, noclass = ISC_FALSE; + +/*% opcode text */ +static const char * const opcodetext[] = { + "QUERY", + "IQUERY", + "STATUS", + "RESERVED3", + "NOTIFY", + "UPDATE", + "RESERVED6", + "RESERVED7", + "RESERVED8", + "RESERVED9", + "RESERVED10", + "RESERVED11", + "RESERVED12", + "RESERVED13", + "RESERVED14", + "RESERVED15" +}; + +/*% return code text */ +static const char * const rcodetext[] = { + "NOERROR", + "FORMERR", + "SERVFAIL", + "NXDOMAIN", + "NOTIMP", + "REFUSED", + "YXDOMAIN", + "YXRRSET", + "NXRRSET", + "NOTAUTH", + "NOTZONE", + "RESERVED11", + "RESERVED12", + "RESERVED13", + "RESERVED14", + "RESERVED15", + "BADVERS" +}; + +/*% safe rcodetext[] */ +static char * +rcode_totext(dns_rcode_t rcode) +{ + static char buf[sizeof("?65535")]; + union { + const char *consttext; + char *deconsttext; + } totext; + + if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) { + snprintf(buf, sizeof(buf), "?%u", rcode); + totext.deconsttext = buf; + } else + totext.consttext = rcodetext[rcode]; + return totext.deconsttext; +} + +/*% print usage */ +static void +print_usage(FILE *fp) { + fputs( +"Usage: dig [@global-server] [domain] [q-type] [q-class] {q-opt}\n" +" {global-d-opt} host [@local-server] {local-d-opt}\n" +" [ host [@local-server] {local-d-opt} [...]]\n", fp); +} + +static void +usage(void) { + print_usage(stderr); + fputs("\nUse \"dig -h\" (or \"dig -h | more\") " + "for complete list of options\n", stderr); + exit(1); +} + +/*% version */ +static void +version(void) { + fputs("DiG " VERSION "\n", stderr); +} + +/*% help */ +static void +help(void) { + print_usage(stdout); + fputs( +"Where: domain is in the Domain Name System\n" +" q-class is one of (in,hs,ch,...) [default: in]\n" +" q-type is one of (a,any,mx,ns,soa,hinfo,axfr,txt,...) [default:a]\n" +" (Use ixfr=version for type ixfr)\n" +" q-opt is one of:\n" +" -x dot-notation (shortcut for reverse lookups)\n" +" -i (use IP6.INT for IPv6 reverse lookups)\n" +" -f filename (batch mode)\n" +" -b address[#port] (bind to source address/port)\n" +" -p port (specify port number)\n" +" -q name (specify query name)\n" +" -t type (specify query type)\n" +" -c class (specify query class)\n" +" -k keyfile (specify tsig key file)\n" +" -y [hmac:]name:key (specify named base64 tsig key)\n" +" -4 (use IPv4 query transport only)\n" +" -6 (use IPv6 query transport only)\n" +" -m (enable memory usage debugging)\n" +" d-opt is of the form +keyword[=value], where keyword is:\n" +" +[no]vc (TCP mode)\n" +" +[no]tcp (TCP mode, alternate syntax)\n" +" +time=### (Set query timeout) [5]\n" +" +tries=### (Set number of UDP attempts) [3]\n" +" +retry=### (Set number of UDP retries) [2]\n" +" +domain=### (Set default domainname)\n" +" +bufsize=### (Set EDNS0 Max UDP packet size)\n" +" +ndots=### (Set NDOTS value)\n" +" +edns=### (Set EDNS version)\n" +" +[no]search (Set whether to use searchlist)\n" +" +[no]showsearch (Search with intermediate results)\n" +" +[no]defname (Ditto)\n" +" +[no]recurse (Recursive mode)\n" +" +[no]ignore (Don't revert to TCP for TC responses.)" +"\n" +" +[no]fail (Don't try next server on SERVFAIL)\n" +" +[no]besteffort (Try to parse even illegal messages)\n" +" +[no]aaonly (Set AA flag in query (+[no]aaflag))\n" +" +[no]adflag (Set AD flag in query)\n" +" +[no]cdflag (Set CD flag in query)\n" +" +[no]cl (Control display of class in records)\n" +" +[no]cmd (Control display of command line)\n" +" +[no]comments (Control display of comment lines)\n" +" +[no]question (Control display of question)\n" +" +[no]answer (Control display of answer)\n" +" +[no]authority (Control display of authority)\n" +" +[no]additional (Control display of additional)\n" +" +[no]stats (Control display of statistics)\n" +" +[no]short (Disable everything except short\n" +" form of answer)\n" +" +[no]ttlid (Control display of ttls in records)\n" +" +[no]all (Set or clear all display flags)\n" +" +[no]qr (Print question before sending)\n" +" +[no]nssearch (Search all authoritative nameservers)\n" +" +[no]identify (ID responders in short answers)\n" +" +[no]trace (Trace delegation down from root)\n" +" +[no]dnssec (Request DNSSEC records)\n" +" +[no]nsid (Request Name Server ID)\n" +#ifdef DIG_SIGCHASE +" +[no]sigchase (Chase DNSSEC signatures)\n" +" +trusted-key=#### (Trusted Key when chasing DNSSEC sigs)\n" +#if DIG_SIGCHASE_TD +" +[no]topdown (Do DNSSEC validation top down mode)\n" +#endif +#endif +" +[no]multiline (Print records in an expanded format)\n" +" global d-opts and servers (before host name) affect all queries.\n" +" local d-opts and servers (after host name) affect only that lookup.\n" +" -h (print help and exit)\n" +" -v (print version and exit)\n", + stdout); +} + +/*% + * Callback from dighost.c to print the received message. + */ +void +received(int bytes, isc_sockaddr_t *from, dig_query_t *query) { + isc_uint64_t diff; + isc_time_t now; + time_t tnow; + char fromtext[ISC_SOCKADDR_FORMATSIZE]; + + isc_sockaddr_format(from, fromtext, sizeof(fromtext)); + + TIME_NOW(&now); + + if (query->lookup->stats && !short_form) { + diff = isc_time_microdiff(&now, &query->time_sent); + printf(";; Query time: %ld msec\n", (long int)diff/1000); + printf(";; SERVER: %s(%s)\n", fromtext, query->servname); + time(&tnow); + printf(";; WHEN: %s", ctime(&tnow)); + if (query->lookup->doing_xfr) { + printf(";; XFR size: %u records (messages %u, " + "bytes %" ISC_PRINT_QUADFORMAT "u)\n", + query->rr_count, query->msg_count, + query->byte_count); + } else { + printf(";; MSG SIZE rcvd: %u\n", bytes); + + } + if (key != NULL) { + if (!validated) + puts(";; WARNING -- Some TSIG could not " + "be validated"); + } + if ((key == NULL) && (keysecret[0] != 0)) { + puts(";; WARNING -- TSIG key was not used."); + } + puts(""); + } else if (query->lookup->identify && !short_form) { + diff = isc_time_microdiff(&now, &query->time_sent); + printf(";; Received %" ISC_PRINT_QUADFORMAT "u bytes " + "from %s(%s) in %d ms\n\n", + query->lookup->doing_xfr ? + query->byte_count : (isc_uint64_t)bytes, + fromtext, query->servname, + (int)diff/1000); + } +} + +/* + * Callback from dighost.c to print that it is trying a server. + * Not used in dig. + * XXX print_trying + */ +void +trying(char *frm, dig_lookup_t *lookup) { + UNUSED(frm); + UNUSED(lookup); +} + +/*% + * Internal print routine used to print short form replies. + */ +static isc_result_t +say_message(dns_rdata_t *rdata, dig_query_t *query, isc_buffer_t *buf) { + isc_result_t result; + isc_uint64_t diff; + isc_time_t now; + char store[sizeof("12345678901234567890")]; + + if (query->lookup->trace || query->lookup->ns_search_only) { + result = dns_rdatatype_totext(rdata->type, buf); + if (result != ISC_R_SUCCESS) + return (result); + ADD_STRING(buf, " "); + } + result = dns_rdata_totext(rdata, NULL, buf); + check_result(result, "dns_rdata_totext"); + if (query->lookup->identify) { + TIME_NOW(&now); + diff = isc_time_microdiff(&now, &query->time_sent); + ADD_STRING(buf, " from server "); + ADD_STRING(buf, query->servname); + snprintf(store, 19, " in %d ms.", (int)diff/1000); + ADD_STRING(buf, store); + } + ADD_STRING(buf, "\n"); + return (ISC_R_SUCCESS); +} + +/*% + * short_form message print handler. Calls above say_message() + */ +static isc_result_t +short_answer(dns_message_t *msg, dns_messagetextflag_t flags, + isc_buffer_t *buf, dig_query_t *query) +{ + dns_name_t *name; + dns_rdataset_t *rdataset; + isc_buffer_t target; + isc_result_t result, loopresult; + dns_name_t empty_name; + char t[4096]; + dns_rdata_t rdata = DNS_RDATA_INIT; + + UNUSED(flags); + + dns_name_init(&empty_name, NULL); + result = dns_message_firstname(msg, DNS_SECTION_ANSWER); + if (result == ISC_R_NOMORE) + return (ISC_R_SUCCESS); + else if (result != ISC_R_SUCCESS) + return (result); + + for (;;) { + name = NULL; + dns_message_currentname(msg, DNS_SECTION_ANSWER, &name); + + isc_buffer_init(&target, t, sizeof(t)); + + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) { + loopresult = dns_rdataset_first(rdataset); + while (loopresult == ISC_R_SUCCESS) { + dns_rdataset_current(rdataset, &rdata); + result = say_message(&rdata, query, + buf); + check_result(result, "say_message"); + loopresult = dns_rdataset_next(rdataset); + dns_rdata_reset(&rdata); + } + } + result = dns_message_nextname(msg, DNS_SECTION_ANSWER); + if (result == ISC_R_NOMORE) + break; + else if (result != ISC_R_SUCCESS) + return (result); + } + + return (ISC_R_SUCCESS); +} +#ifdef DIG_SIGCHASE +isc_result_t +printrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset, + isc_buffer_t *target) +{ + isc_result_t result; + dns_master_style_t *style = NULL; + unsigned int styleflags = 0; + + if (rdataset == NULL || owner_name == NULL || target == NULL) + return(ISC_FALSE); + + styleflags |= DNS_STYLEFLAG_REL_OWNER; + if (nottl) + styleflags |= DNS_STYLEFLAG_NO_TTL; + if (noclass) + styleflags |= DNS_STYLEFLAG_NO_CLASS; + if (multiline) { + styleflags |= DNS_STYLEFLAG_OMIT_OWNER; + styleflags |= DNS_STYLEFLAG_OMIT_CLASS; + styleflags |= DNS_STYLEFLAG_REL_DATA; + styleflags |= DNS_STYLEFLAG_OMIT_TTL; + styleflags |= DNS_STYLEFLAG_TTL; + styleflags |= DNS_STYLEFLAG_MULTILINE; + styleflags |= DNS_STYLEFLAG_COMMENT; + } + if (multiline || (nottl && noclass)) + result = dns_master_stylecreate(&style, styleflags, + 24, 24, 24, 32, 80, 8, mctx); + else if (nottl || noclass) + result = dns_master_stylecreate(&style, styleflags, + 24, 24, 32, 40, 80, 8, mctx); + else + result = dns_master_stylecreate(&style, styleflags, + 24, 32, 40, 48, 80, 8, mctx); + check_result(result, "dns_master_stylecreate"); + + result = dns_master_rdatasettotext(owner_name, rdataset, style, target); + + if (style != NULL) + dns_master_styledestroy(&style, mctx); + + return(result); +} +#endif + +/* + * Callback from dighost.c to print the reply from a server + */ +isc_result_t +printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { + isc_result_t result; + dns_messagetextflag_t flags; + isc_buffer_t *buf = NULL; + unsigned int len = OUTPUTBUF; + dns_master_style_t *style = NULL; + unsigned int styleflags = 0; + + styleflags |= DNS_STYLEFLAG_REL_OWNER; + if (nottl) + styleflags |= DNS_STYLEFLAG_NO_TTL; + if (noclass) + styleflags |= DNS_STYLEFLAG_NO_CLASS; + if (multiline) { + styleflags |= DNS_STYLEFLAG_OMIT_OWNER; + styleflags |= DNS_STYLEFLAG_OMIT_CLASS; + styleflags |= DNS_STYLEFLAG_REL_DATA; + styleflags |= DNS_STYLEFLAG_OMIT_TTL; + styleflags |= DNS_STYLEFLAG_TTL; + styleflags |= DNS_STYLEFLAG_MULTILINE; + styleflags |= DNS_STYLEFLAG_COMMENT; + } + if (multiline || (nottl && noclass)) + result = dns_master_stylecreate(&style, styleflags, + 24, 24, 24, 32, 80, 8, mctx); + else if (nottl || noclass) + result = dns_master_stylecreate(&style, styleflags, + 24, 24, 32, 40, 80, 8, mctx); + else + result = dns_master_stylecreate(&style, styleflags, + 24, 32, 40, 48, 80, 8, mctx); + check_result(result, "dns_master_stylecreate"); + + if (query->lookup->cmdline[0] != 0) { + if (!short_form) + fputs(query->lookup->cmdline, stdout); + query->lookup->cmdline[0]=0; + } + debug("printmessage(%s %s %s)", headers ? "headers" : "noheaders", + query->lookup->comments ? "comments" : "nocomments", + short_form ? "short_form" : "long_form"); + + flags = 0; + if (!headers) { + flags |= DNS_MESSAGETEXTFLAG_NOHEADERS; + flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS; + } + if (!query->lookup->comments) + flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS; + + result = ISC_R_SUCCESS; + + result = isc_buffer_allocate(mctx, &buf, len); + check_result(result, "isc_buffer_allocate"); + + if (query->lookup->comments && !short_form) { + if (query->lookup->cmdline[0] != 0) + printf("; %s\n", query->lookup->cmdline); + if (msg == query->lookup->sendmsg) + printf(";; Sending:\n"); + else + printf(";; Got answer:\n"); + + if (headers) { + printf(";; ->>HEADER<<- opcode: %s, status: %s, " + "id: %u\n", + opcodetext[msg->opcode], + rcode_totext(msg->rcode), + msg->id); + printf(";; flags:"); + if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) + printf(" qr"); + if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) + printf(" aa"); + if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) + printf(" tc"); + if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) + printf(" rd"); + if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) + printf(" ra"); + if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) + printf(" ad"); + if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) + printf(" cd"); + + printf("; QUERY: %u, ANSWER: %u, " + "AUTHORITY: %u, ADDITIONAL: %u\n", + msg->counts[DNS_SECTION_QUESTION], + msg->counts[DNS_SECTION_ANSWER], + msg->counts[DNS_SECTION_AUTHORITY], + msg->counts[DNS_SECTION_ADDITIONAL]); + + if (msg != query->lookup->sendmsg && + (msg->flags & DNS_MESSAGEFLAG_RD) != 0 && + (msg->flags & DNS_MESSAGEFLAG_RA) == 0) + printf(";; WARNING: recursion requested " + "but not available\n"); + } + if (msg != query->lookup->sendmsg && extrabytes != 0U) + printf(";; WARNING: Messages has %u extra byte%s at " + "end\n", extrabytes, extrabytes != 0 ? "s" : ""); + } + +repopulate_buffer: + + if (query->lookup->comments && headers && !short_form) { + result = dns_message_pseudosectiontotext(msg, + DNS_PSEUDOSECTION_OPT, + style, flags, buf); + if (result == ISC_R_NOSPACE) { +buftoosmall: + len += OUTPUTBUF; + isc_buffer_free(&buf); + result = isc_buffer_allocate(mctx, &buf, len); + if (result == ISC_R_SUCCESS) + goto repopulate_buffer; + else + goto cleanup; + } + check_result(result, + "dns_message_pseudosectiontotext"); + } + + if (query->lookup->section_question && headers) { + if (!short_form) { + result = dns_message_sectiontotext(msg, + DNS_SECTION_QUESTION, + style, flags, buf); + if (result == ISC_R_NOSPACE) + goto buftoosmall; + check_result(result, "dns_message_sectiontotext"); + } + } + if (query->lookup->section_answer) { + if (!short_form) { + result = dns_message_sectiontotext(msg, + DNS_SECTION_ANSWER, + style, flags, buf); + if (result == ISC_R_NOSPACE) + goto buftoosmall; + check_result(result, "dns_message_sectiontotext"); + } else { + result = short_answer(msg, flags, buf, query); + if (result == ISC_R_NOSPACE) + goto buftoosmall; + check_result(result, "short_answer"); + } + } + if (query->lookup->section_authority) { + if (!short_form) { + result = dns_message_sectiontotext(msg, + DNS_SECTION_AUTHORITY, + style, flags, buf); + if (result == ISC_R_NOSPACE) + goto buftoosmall; + check_result(result, "dns_message_sectiontotext"); + } + } + if (query->lookup->section_additional) { + if (!short_form) { + result = dns_message_sectiontotext(msg, + DNS_SECTION_ADDITIONAL, + style, flags, buf); + if (result == ISC_R_NOSPACE) + goto buftoosmall; + check_result(result, "dns_message_sectiontotext"); + /* + * Only print the signature on the first record. + */ + if (headers) { + result = dns_message_pseudosectiontotext( + msg, + DNS_PSEUDOSECTION_TSIG, + style, flags, buf); + if (result == ISC_R_NOSPACE) + goto buftoosmall; + check_result(result, + "dns_message_pseudosectiontotext"); + result = dns_message_pseudosectiontotext( + msg, + DNS_PSEUDOSECTION_SIG0, + style, flags, buf); + if (result == ISC_R_NOSPACE) + goto buftoosmall; + check_result(result, + "dns_message_pseudosectiontotext"); + } + } + } + + if (headers && query->lookup->comments && !short_form) + printf("\n"); + + printf("%.*s", (int)isc_buffer_usedlength(buf), + (char *)isc_buffer_base(buf)); + isc_buffer_free(&buf); + +cleanup: + if (style != NULL) + dns_master_styledestroy(&style, mctx); + return (result); +} + +/*% + * print the greeting message when the program first starts up. + */ +static void +printgreeting(int argc, char **argv, dig_lookup_t *lookup) { + int i; + int remaining; + static isc_boolean_t first = ISC_TRUE; + char append[MXNAME]; + + if (printcmd) { + lookup->cmdline[sizeof(lookup->cmdline) - 1] = 0; + snprintf(lookup->cmdline, sizeof(lookup->cmdline), + "%s; <<>> DiG " VERSION " <<>>", + first?"\n":""); + i = 1; + while (i < argc) { + snprintf(append, sizeof(append), " %s", argv[i++]); + remaining = sizeof(lookup->cmdline) - + strlen(lookup->cmdline) - 1; + strncat(lookup->cmdline, append, remaining); + } + remaining = sizeof(lookup->cmdline) - + strlen(lookup->cmdline) - 1; + strncat(lookup->cmdline, "\n", remaining); + if (first && addresscount != 0) { + snprintf(append, sizeof(append), + "; (%d server%s found)\n", + addresscount, + addresscount > 1 ? "s" : ""); + remaining = sizeof(lookup->cmdline) - + strlen(lookup->cmdline) - 1; + strncat(lookup->cmdline, append, remaining); + } + if (first) { + snprintf(append, sizeof(append), + ";; global options: %s %s\n", + short_form ? "short_form" : "", + printcmd ? "printcmd" : ""); + first = ISC_FALSE; + remaining = sizeof(lookup->cmdline) - + strlen(lookup->cmdline) - 1; + strncat(lookup->cmdline, append, remaining); + } + } +} + +static isc_uint32_t +parse_uint(char *arg, const char *desc, isc_uint32_t max) { + isc_result_t result; + isc_uint32_t tmp; + + result = isc_parse_uint32(&tmp, arg, 10); + if (result == ISC_R_SUCCESS && tmp > max) + result = ISC_R_RANGE; + if (result != ISC_R_SUCCESS) + fatal("%s '%s': %s", desc, arg, isc_result_totext(result)); + return (tmp); +} + +/*% + * We're not using isc_commandline_parse() here since the command line + * syntax of dig is quite a bit different from that which can be described + * by that routine. + * XXX doc options + */ + +static void +plus_option(char *option, isc_boolean_t is_batchfile, + dig_lookup_t *lookup) +{ + char option_store[256]; + char *cmd, *value, *ptr; + isc_boolean_t state = ISC_TRUE; +#ifdef DIG_SIGCHASE + size_t n; +#endif + + strncpy(option_store, option, sizeof(option_store)); + option_store[sizeof(option_store)-1]=0; + ptr = option_store; + cmd = next_token(&ptr,"="); + if (cmd == NULL) { + printf(";; Invalid option %s\n", option_store); + return; + } + value = ptr; + if (strncasecmp(cmd, "no", 2)==0) { + cmd += 2; + state = ISC_FALSE; + } + +#define FULLCHECK(A) \ + do { \ + size_t _l = strlen(cmd); \ + if (_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) \ + goto invalid_option; \ + } while (0) +#define FULLCHECK2(A, B) \ + do { \ + size_t _l = strlen(cmd); \ + if ((_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) && \ + (_l >= sizeof(B) || strncasecmp(cmd, B, _l) != 0)) \ + goto invalid_option; \ + } while (0) + + switch (cmd[0]) { + case 'a': + switch (cmd[1]) { + case 'a': /* aaonly / aaflag */ + FULLCHECK2("aaonly", "aaflag"); + lookup->aaonly = state; + break; + case 'd': + switch (cmd[2]) { + case 'd': /* additional */ + FULLCHECK("additional"); + lookup->section_additional = state; + break; + case 'f': /* adflag */ + FULLCHECK("adflag"); + lookup->adflag = state; + break; + default: + goto invalid_option; + } + break; + case 'l': /* all */ + FULLCHECK("all"); + lookup->section_question = state; + lookup->section_authority = state; + lookup->section_answer = state; + lookup->section_additional = state; + lookup->comments = state; + lookup->stats = state; + printcmd = state; + break; + case 'n': /* answer */ + FULLCHECK("answer"); + lookup->section_answer = state; + break; + case 'u': /* authority */ + FULLCHECK("authority"); + lookup->section_authority = state; + break; + default: + goto invalid_option; + } + break; + case 'b': + switch (cmd[1]) { + case 'e':/* besteffort */ + FULLCHECK("besteffort"); + lookup->besteffort = state; + break; + case 'u':/* bufsize */ + FULLCHECK("bufsize"); + if (value == NULL) + goto need_value; + if (!state) + goto invalid_option; + lookup->udpsize = (isc_uint16_t) parse_uint(value, + "buffer size", COMMSIZE); + break; + default: + goto invalid_option; + } + break; + case 'c': + switch (cmd[1]) { + case 'd':/* cdflag */ + FULLCHECK("cdflag"); + lookup->cdflag = state; + break; + case 'l': /* cl */ + FULLCHECK("cl"); + noclass = ISC_TF(!state); + break; + case 'm': /* cmd */ + FULLCHECK("cmd"); + printcmd = state; + break; + case 'o': /* comments */ + FULLCHECK("comments"); + lookup->comments = state; + if (lookup == default_lookup) + pluscomm = state; + break; + default: + goto invalid_option; + } + break; + case 'd': + switch (cmd[1]) { + case 'e': /* defname */ + FULLCHECK("defname"); + if (!lookup->trace) { + usesearch = state; + } + break; + case 'n': /* dnssec */ + FULLCHECK("dnssec"); + if (state && lookup->edns == -1) + lookup->edns = 0; + lookup->dnssec = state; + break; + case 'o': /* domain */ + FULLCHECK("domain"); + if (value == NULL) + goto need_value; + if (!state) + goto invalid_option; + strncpy(domainopt, value, sizeof(domainopt)); + domainopt[sizeof(domainopt)-1] = '\0'; + break; + default: + goto invalid_option; + } + break; + case 'e': + FULLCHECK("edns"); + if (!state) { + lookup->edns = -1; + break; + } + if (value == NULL) + goto need_value; + lookup->edns = (isc_int16_t) parse_uint(value, "edns", 255); + break; + case 'f': /* fail */ + FULLCHECK("fail"); + lookup->servfail_stops = state; + break; + case 'i': + switch (cmd[1]) { + case 'd': /* identify */ + FULLCHECK("identify"); + lookup->identify = state; + break; + case 'g': /* ignore */ + default: /* Inherits default for compatibility */ + FULLCHECK("ignore"); + lookup->ignore = ISC_TRUE; + } + break; + case 'm': /* multiline */ + FULLCHECK("multiline"); + multiline = state; + break; + case 'n': + switch (cmd[1]) { + case 'd': /* ndots */ + FULLCHECK("ndots"); + if (value == NULL) + goto need_value; + if (!state) + goto invalid_option; + ndots = parse_uint(value, "ndots", MAXNDOTS); + break; + case 's': + switch (cmd[2]) { + case 'i': /* nsid */ + FULLCHECK("nsid"); + if (state && lookup->edns == -1) + lookup->edns = 0; + lookup->nsid = state; + break; + case 's': /* nssearch */ + FULLCHECK("nssearch"); + lookup->ns_search_only = state; + if (state) { + lookup->trace_root = ISC_TRUE; + lookup->recurse = ISC_TRUE; + lookup->identify = ISC_TRUE; + lookup->stats = ISC_FALSE; + lookup->comments = ISC_FALSE; + lookup->section_additional = ISC_FALSE; + lookup->section_authority = ISC_FALSE; + lookup->section_question = ISC_FALSE; + lookup->rdtype = dns_rdatatype_ns; + lookup->rdtypeset = ISC_TRUE; + short_form = ISC_TRUE; + } + break; + default: + goto invalid_option; + } + break; + default: + goto invalid_option; + } + break; + case 'q': + switch (cmd[1]) { + case 'r': /* qr */ + FULLCHECK("qr"); + qr = state; + break; + case 'u': /* question */ + FULLCHECK("question"); + lookup->section_question = state; + if (lookup == default_lookup) + plusquest = state; + break; + default: + goto invalid_option; + } + break; + case 'r': + switch (cmd[1]) { + case 'e': + switch (cmd[2]) { + case 'c': /* recurse */ + FULLCHECK("recurse"); + lookup->recurse = state; + break; + case 't': /* retry / retries */ + FULLCHECK2("retry", "retries"); + if (value == NULL) + goto need_value; + if (!state) + goto invalid_option; + lookup->retries = parse_uint(value, "retries", + MAXTRIES - 1); + lookup->retries++; + break; + default: + goto invalid_option; + } + break; + default: + goto invalid_option; + } + break; + case 's': + switch (cmd[1]) { + case 'e': /* search */ + FULLCHECK("search"); + if (!lookup->trace) { + usesearch = state; + } + break; + case 'h': + if (cmd[2] != 'o') + goto invalid_option; + switch (cmd[3]) { + case 'r': /* short */ + FULLCHECK("short"); + short_form = state; + if (state) { + printcmd = ISC_FALSE; + lookup->section_additional = ISC_FALSE; + lookup->section_answer = ISC_TRUE; + lookup->section_authority = ISC_FALSE; + lookup->section_question = ISC_FALSE; + lookup->comments = ISC_FALSE; + lookup->stats = ISC_FALSE; + } + break; + case 'w': /* showsearch */ + FULLCHECK("showsearch"); + if (!lookup->trace) { + showsearch = state; + usesearch = state; + } + break; + default: + goto invalid_option; + } + break; +#ifdef DIG_SIGCHASE + case 'i': /* sigchase */ + FULLCHECK("sigchase"); + lookup->sigchase = state; + if (lookup->sigchase) + lookup->dnssec = ISC_TRUE; + break; +#endif + case 't': /* stats */ + FULLCHECK("stats"); + lookup->stats = state; + break; + default: + goto invalid_option; + } + break; + case 't': + switch (cmd[1]) { + case 'c': /* tcp */ + FULLCHECK("tcp"); + if (!is_batchfile) + lookup->tcp_mode = state; + break; + case 'i': /* timeout */ + FULLCHECK("timeout"); + if (value == NULL) + goto need_value; + if (!state) + goto invalid_option; + timeout = parse_uint(value, "timeout", MAXTIMEOUT); + if (timeout == 0) + timeout = 1; + break; +#if DIG_SIGCHASE_TD + case 'o': /* topdown */ + FULLCHECK("topdown"); + lookup->do_topdown = state; + break; +#endif + case 'r': + switch (cmd[2]) { + case 'a': /* trace */ + FULLCHECK("trace"); + lookup->trace = state; + lookup->trace_root = state; + if (state) { + lookup->recurse = ISC_FALSE; + lookup->identify = ISC_TRUE; + lookup->comments = ISC_FALSE; + lookup->stats = ISC_FALSE; + lookup->section_additional = ISC_FALSE; + lookup->section_authority = ISC_TRUE; + lookup->section_question = ISC_FALSE; + usesearch = ISC_FALSE; + } + break; + case 'i': /* tries */ + FULLCHECK("tries"); + if (value == NULL) + goto need_value; + if (!state) + goto invalid_option; + lookup->retries = parse_uint(value, "tries", + MAXTRIES); + if (lookup->retries == 0) + lookup->retries = 1; + break; +#ifdef DIG_SIGCHASE + case 'u': /* trusted-key */ + FULLCHECK("trusted-key"); + if (value == NULL) + goto need_value; + if (!state) + goto invalid_option; + n = strlcpy(trustedkey, ptr, + sizeof(trustedkey)); + if (n >= sizeof(trustedkey)) + fatal("trusted key too large"); + break; +#endif + default: + goto invalid_option; + } + break; + case 't': /* ttlid */ + FULLCHECK("ttlid"); + nottl = ISC_TF(!state); + break; + default: + goto invalid_option; + } + break; + case 'v': + FULLCHECK("vc"); + if (!is_batchfile) + lookup->tcp_mode = state; + break; + default: + invalid_option: + need_value: + fprintf(stderr, "Invalid option: +%s\n", + option); + usage(); + } + return; +} + +/*% + * #ISC_TRUE returned if value was used + */ +static const char *single_dash_opts = "46dhimnv"; +static const char *dash_opts = "46bcdfhikmnptvyx"; +static isc_boolean_t +dash_option(char *option, char *next, dig_lookup_t **lookup, + isc_boolean_t *open_type_class, isc_boolean_t *need_clone, + isc_boolean_t config_only, int argc, char **argv, + isc_boolean_t *firstarg) +{ + char opt, *value, *ptr, *ptr2, *ptr3; + isc_result_t result; + isc_boolean_t value_from_next; + isc_textregion_t tr; + dns_rdatatype_t rdtype; + dns_rdataclass_t rdclass; + char textname[MXNAME]; + struct in_addr in4; + struct in6_addr in6; + in_port_t srcport; + char *hash, *cmd; + + while (strpbrk(option, single_dash_opts) == &option[0]) { + /* + * Since the -[46dhimnv] options do not take an argument, + * account for them (in any number and/or combination) + * if they appear as the first character(s) of a q-opt. + */ + opt = option[0]; + switch (opt) { + case '4': + if (have_ipv4) { + isc_net_disableipv6(); + have_ipv6 = ISC_FALSE; + } else { + fatal("can't find IPv4 networking"); + return (ISC_FALSE); + } + break; + case '6': + if (have_ipv6) { + isc_net_disableipv4(); + have_ipv4 = ISC_FALSE; + } else { + fatal("can't find IPv6 networking"); + return (ISC_FALSE); + } + break; + case 'd': + ptr = strpbrk(&option[1], dash_opts); + if (ptr != &option[1]) { + cmd = option; + FULLCHECK("debug"); + debugging = ISC_TRUE; + return (ISC_FALSE); + } else + debugging = ISC_TRUE; + break; + case 'h': + help(); + exit(0); + break; + case 'i': + ip6_int = ISC_TRUE; + break; + case 'm': /* memdebug */ + /* memdebug is handled in preparse_args() */ + break; + case 'n': + /* deprecated */ + break; + case 'v': + version(); + exit(0); + break; + } + if (strlen(option) > 1U) + option = &option[1]; + else + return (ISC_FALSE); + } + opt = option[0]; + if (strlen(option) > 1U) { + value_from_next = ISC_FALSE; + value = &option[1]; + } else { + value_from_next = ISC_TRUE; + value = next; + } + if (value == NULL) + goto invalid_option; + switch (opt) { + case 'b': + hash = strchr(value, '#'); + if (hash != NULL) { + srcport = (in_port_t) + parse_uint(hash + 1, + "port number", MAXPORT); + *hash = '\0'; + } else + srcport = 0; + if (have_ipv6 && inet_pton(AF_INET6, value, &in6) == 1) { + isc_sockaddr_fromin6(&bind_address, &in6, srcport); + isc_net_disableipv4(); + } else if (have_ipv4 && inet_pton(AF_INET, value, &in4) == 1) { + isc_sockaddr_fromin(&bind_address, &in4, srcport); + isc_net_disableipv6(); + } else { + if (hash != NULL) + *hash = '#'; + fatal("invalid address %s", value); + } + if (hash != NULL) + *hash = '#'; + specified_source = ISC_TRUE; + return (value_from_next); + case 'c': + if ((*lookup)->rdclassset) { + fprintf(stderr, ";; Warning, extra class option\n"); + } + *open_type_class = ISC_FALSE; + tr.base = value; + tr.length = strlen(value); + result = dns_rdataclass_fromtext(&rdclass, + (isc_textregion_t *)&tr); + if (result == ISC_R_SUCCESS) { + (*lookup)->rdclass = rdclass; + (*lookup)->rdclassset = ISC_TRUE; + } else + fprintf(stderr, ";; Warning, ignoring " + "invalid class %s\n", + value); + return (value_from_next); + case 'f': + batchname = value; + return (value_from_next); + case 'k': + strncpy(keyfile, value, sizeof(keyfile)); + keyfile[sizeof(keyfile)-1]=0; + return (value_from_next); + case 'p': + port = (in_port_t) parse_uint(value, "port number", MAXPORT); + return (value_from_next); + case 'q': + if (!config_only) { + if (*need_clone) + (*lookup) = clone_lookup(default_lookup, + ISC_TRUE); + *need_clone = ISC_TRUE; + strncpy((*lookup)->textname, value, + sizeof((*lookup)->textname)); + (*lookup)->textname[sizeof((*lookup)->textname)-1]=0; + (*lookup)->trace_root = ISC_TF((*lookup)->trace || + (*lookup)->ns_search_only); + (*lookup)->new_search = ISC_TRUE; + if (*firstarg) { + printgreeting(argc, argv, *lookup); + *firstarg = ISC_FALSE; + } + ISC_LIST_APPEND(lookup_list, (*lookup), link); + debug("looking up %s", (*lookup)->textname); + } + return (value_from_next); + case 't': + *open_type_class = ISC_FALSE; + if (strncasecmp(value, "ixfr=", 5) == 0) { + rdtype = dns_rdatatype_ixfr; + result = ISC_R_SUCCESS; + } else { + tr.base = value; + tr.length = strlen(value); + result = dns_rdatatype_fromtext(&rdtype, + (isc_textregion_t *)&tr); + if (result == ISC_R_SUCCESS && + rdtype == dns_rdatatype_ixfr) { + result = DNS_R_UNKNOWN; + } + } + if (result == ISC_R_SUCCESS) { + if ((*lookup)->rdtypeset) { + fprintf(stderr, ";; Warning, " + "extra type option\n"); + } + if (rdtype == dns_rdatatype_ixfr) { + (*lookup)->rdtype = dns_rdatatype_ixfr; + (*lookup)->rdtypeset = ISC_TRUE; + (*lookup)->ixfr_serial = + parse_uint(&value[5], "serial number", + MAXSERIAL); + (*lookup)->section_question = plusquest; + (*lookup)->comments = pluscomm; + (*lookup)->tcp_mode = ISC_TRUE; + } else { + (*lookup)->rdtype = rdtype; + (*lookup)->rdtypeset = ISC_TRUE; + if (rdtype == dns_rdatatype_axfr) { + (*lookup)->section_question = plusquest; + (*lookup)->comments = pluscomm; + } + (*lookup)->ixfr_serial = ISC_FALSE; + } + } else + fprintf(stderr, ";; Warning, ignoring " + "invalid type %s\n", + value); + return (value_from_next); + case 'y': + ptr = next_token(&value,":"); /* hmac type or name */ + if (ptr == NULL) { + usage(); + } + ptr2 = next_token(&value, ":"); /* name or secret */ + if (ptr2 == NULL) + usage(); + ptr3 = next_token(&value,":"); /* secret or NULL */ + if (ptr3 != NULL) { + if (strcasecmp(ptr, "hmac-md5") == 0) { + hmacname = DNS_TSIG_HMACMD5_NAME; + digestbits = 0; + } else if (strncasecmp(ptr, "hmac-md5-", 9) == 0) { + hmacname = DNS_TSIG_HMACMD5_NAME; + digestbits = parse_uint(&ptr[9], + "digest-bits [0..128]", + 128); + digestbits = (digestbits + 7) & ~0x7U; + } else if (strcasecmp(ptr, "hmac-sha1") == 0) { + hmacname = DNS_TSIG_HMACSHA1_NAME; + digestbits = 0; + } else if (strncasecmp(ptr, "hmac-sha1-", 10) == 0) { + hmacname = DNS_TSIG_HMACSHA1_NAME; + digestbits = parse_uint(&ptr[10], + "digest-bits [0..160]", + 160); + digestbits = (digestbits + 7) & ~0x7U; + } else if (strcasecmp(ptr, "hmac-sha224") == 0) { + hmacname = DNS_TSIG_HMACSHA224_NAME; + digestbits = 0; + } else if (strncasecmp(ptr, "hmac-sha224-", 12) == 0) { + hmacname = DNS_TSIG_HMACSHA224_NAME; + digestbits = parse_uint(&ptr[12], + "digest-bits [0..224]", + 224); + digestbits = (digestbits + 7) & ~0x7U; + } else if (strcasecmp(ptr, "hmac-sha256") == 0) { + hmacname = DNS_TSIG_HMACSHA256_NAME; + digestbits = 0; + } else if (strncasecmp(ptr, "hmac-sha256-", 12) == 0) { + hmacname = DNS_TSIG_HMACSHA256_NAME; + digestbits = parse_uint(&ptr[12], + "digest-bits [0..256]", + 256); + digestbits = (digestbits + 7) & ~0x7U; + } else if (strcasecmp(ptr, "hmac-sha384") == 0) { + hmacname = DNS_TSIG_HMACSHA384_NAME; + digestbits = 0; + } else if (strncasecmp(ptr, "hmac-sha384-", 12) == 0) { + hmacname = DNS_TSIG_HMACSHA384_NAME; + digestbits = parse_uint(&ptr[12], + "digest-bits [0..384]", + 384); + digestbits = (digestbits + 7) & ~0x7U; + } else if (strcasecmp(ptr, "hmac-sha512") == 0) { + hmacname = DNS_TSIG_HMACSHA512_NAME; + digestbits = 0; + } else if (strncasecmp(ptr, "hmac-sha512-", 12) == 0) { + hmacname = DNS_TSIG_HMACSHA512_NAME; + digestbits = parse_uint(&ptr[12], + "digest-bits [0..512]", + 512); + digestbits = (digestbits + 7) & ~0x7U; + } else { + fprintf(stderr, ";; Warning, ignoring " + "invalid TSIG algorithm %s\n", ptr); + return (value_from_next); + } + ptr = ptr2; + ptr2 = ptr3; + } else { + hmacname = DNS_TSIG_HMACMD5_NAME; + digestbits = 0; + } + strncpy(keynametext, ptr, sizeof(keynametext)); + keynametext[sizeof(keynametext)-1]=0; + strncpy(keysecret, ptr2, sizeof(keysecret)); + keysecret[sizeof(keysecret)-1]=0; + return (value_from_next); + case 'x': + if (*need_clone) + *lookup = clone_lookup(default_lookup, ISC_TRUE); + *need_clone = ISC_TRUE; + if (get_reverse(textname, sizeof(textname), value, + ip6_int, ISC_FALSE) == ISC_R_SUCCESS) { + strncpy((*lookup)->textname, textname, + sizeof((*lookup)->textname)); + debug("looking up %s", (*lookup)->textname); + (*lookup)->trace_root = ISC_TF((*lookup)->trace || + (*lookup)->ns_search_only); + (*lookup)->ip6_int = ip6_int; + if (!(*lookup)->rdtypeset) + (*lookup)->rdtype = dns_rdatatype_ptr; + if (!(*lookup)->rdclassset) + (*lookup)->rdclass = dns_rdataclass_in; + (*lookup)->new_search = ISC_TRUE; + if (*firstarg) { + printgreeting(argc, argv, *lookup); + *firstarg = ISC_FALSE; + } + ISC_LIST_APPEND(lookup_list, *lookup, link); + } else { + fprintf(stderr, "Invalid IP address %s\n", value); + exit(1); + } + return (value_from_next); + invalid_option: + default: + fprintf(stderr, "Invalid option: -%s\n", option); + usage(); + } + return (ISC_FALSE); +} + +/*% + * Because we may be trying to do memory allocation recording, we're going + * to need to parse the arguments for the -m *before* we start the main + * argument parsing routine. + * + * I'd prefer not to have to do this, but I am not quite sure how else to + * fix the problem. Argument parsing in dig involves memory allocation + * by its nature, so it can't be done in the main argument parser. + */ +static void +preparse_args(int argc, char **argv) { + int rc; + char **rv; + char *option; + + rc = argc; + rv = argv; + for (rc--, rv++; rc > 0; rc--, rv++) { + if (rv[0][0] != '-') + continue; + option = &rv[0][1]; + while (strpbrk(option, single_dash_opts) == &option[0]) { + if (option[0] == 'm') { + memdebugging = ISC_TRUE; + isc_mem_debugging = ISC_MEM_DEBUGTRACE | + ISC_MEM_DEBUGRECORD; + return; + } + option = &option[1]; + } + } +} + +static void +getaddresses(dig_lookup_t *lookup, const char *host) { + isc_result_t result; + isc_sockaddr_t sockaddrs[DIG_MAX_ADDRESSES]; + isc_netaddr_t netaddr; + int count, i; + dig_server_t *srv; + char tmp[ISC_NETADDR_FORMATSIZE]; + + result = bind9_getaddresses(host, 0, sockaddrs, + DIG_MAX_ADDRESSES, &count); + if (result != ISC_R_SUCCESS) + fatal("couldn't get address for '%s': %s", + host, isc_result_totext(result)); + + for (i = 0; i < count; i++) { + isc_netaddr_fromsockaddr(&netaddr, &sockaddrs[i]); + isc_netaddr_format(&netaddr, tmp, sizeof(tmp)); + srv = make_server(tmp, host); + ISC_LIST_APPEND(lookup->my_server_list, srv, link); + } + addresscount = count; +} + +static void +parse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only, + int argc, char **argv) { + isc_result_t result; + isc_textregion_t tr; + isc_boolean_t firstarg = ISC_TRUE; + dig_lookup_t *lookup = NULL; + dns_rdatatype_t rdtype; + dns_rdataclass_t rdclass; + isc_boolean_t open_type_class = ISC_TRUE; + char batchline[MXNAME]; + int bargc; + char *bargv[64]; + int rc; + char **rv; +#ifndef NOPOSIX + char *homedir; + char rcfile[256]; +#endif + char *input; + int i; + isc_boolean_t need_clone = ISC_TRUE; + + /* + * The semantics for parsing the args is a bit complex; if + * we don't have a host yet, make the arg apply globally, + * otherwise make it apply to the latest host. This is + * a bit different than the previous versions, but should + * form a consistent user interface. + * + * First, create a "default lookup" which won't actually be used + * anywhere, except for cloning into new lookups + */ + + debug("parse_args()"); + if (!is_batchfile) { + debug("making new lookup"); + default_lookup = make_empty_lookup(); + +#ifndef NOPOSIX + /* + * Treat ${HOME}/.digrc as a special batchfile + */ + INSIST(batchfp == NULL); + homedir = getenv("HOME"); + if (homedir != NULL) { + unsigned int n; + n = snprintf(rcfile, sizeof(rcfile), "%s/.digrc", + homedir); + if (n < sizeof(rcfile)) + batchfp = fopen(rcfile, "r"); + } + if (batchfp != NULL) { + while (fgets(batchline, sizeof(batchline), + batchfp) != 0) { + debug("config line %s", batchline); + bargc = 1; + input = batchline; + bargv[bargc] = next_token(&input, " \t\r\n"); + while ((bargv[bargc] != NULL) && + (bargc < 62)) { + bargc++; + bargv[bargc] = + next_token(&input, " \t\r\n"); + } + + bargv[0] = argv[0]; + argv0 = argv[0]; + + for(i = 0; i < bargc; i++) + debug(".digrc argv %d: %s", + i, bargv[i]); + parse_args(ISC_TRUE, ISC_TRUE, bargc, + (char **)bargv); + } + fclose(batchfp); + } +#endif + } + + if (is_batchfile && !config_only) { + /* Processing '-f batchfile'. */ + lookup = clone_lookup(default_lookup, ISC_TRUE); + need_clone = ISC_FALSE; + } else + lookup = default_lookup; + + rc = argc; + rv = argv; + for (rc--, rv++; rc > 0; rc--, rv++) { + debug("main parsing %s", rv[0]); + if (strncmp(rv[0], "%", 1) == 0) + break; + if (strncmp(rv[0], "@", 1) == 0) { + getaddresses(lookup, &rv[0][1]); + } else if (rv[0][0] == '+') { + plus_option(&rv[0][1], is_batchfile, + lookup); + } else if (rv[0][0] == '-') { + if (rc <= 1) { + if (dash_option(&rv[0][1], NULL, + &lookup, &open_type_class, + &need_clone, config_only, + argc, argv, &firstarg)) { + rc--; + rv++; + } + } else { + if (dash_option(&rv[0][1], rv[1], + &lookup, &open_type_class, + &need_clone, config_only, + argc, argv, &firstarg)) { + rc--; + rv++; + } + } + } else { + /* + * Anything which isn't an option + */ + if (open_type_class) { + if (strncasecmp(rv[0], "ixfr=", 5) == 0) { + rdtype = dns_rdatatype_ixfr; + result = ISC_R_SUCCESS; + } else { + tr.base = rv[0]; + tr.length = strlen(rv[0]); + result = dns_rdatatype_fromtext(&rdtype, + (isc_textregion_t *)&tr); + if (result == ISC_R_SUCCESS && + rdtype == dns_rdatatype_ixfr) { + result = DNS_R_UNKNOWN; + fprintf(stderr, ";; Warning, " + "ixfr requires a " + "serial number\n"); + continue; + } + } + if (result == ISC_R_SUCCESS) { + if (lookup->rdtypeset) { + fprintf(stderr, ";; Warning, " + "extra type option\n"); + } + if (rdtype == dns_rdatatype_ixfr) { + lookup->rdtype = + dns_rdatatype_ixfr; + lookup->rdtypeset = ISC_TRUE; + lookup->ixfr_serial = + parse_uint(&rv[0][5], + "serial number", + MAXSERIAL); + lookup->section_question = + plusquest; + lookup->comments = pluscomm; + lookup->tcp_mode = ISC_TRUE; + } else { + lookup->rdtype = rdtype; + lookup->rdtypeset = ISC_TRUE; + if (rdtype == + dns_rdatatype_axfr) { + lookup->section_question = + plusquest; + lookup->comments = pluscomm; + } + lookup->ixfr_serial = ISC_FALSE; + } + continue; + } + result = dns_rdataclass_fromtext(&rdclass, + (isc_textregion_t *)&tr); + if (result == ISC_R_SUCCESS) { + if (lookup->rdclassset) { + fprintf(stderr, ";; Warning, " + "extra class option\n"); + } + lookup->rdclass = rdclass; + lookup->rdclassset = ISC_TRUE; + continue; + } + } + + if (!config_only) { + if (need_clone) + lookup = clone_lookup(default_lookup, + ISC_TRUE); + need_clone = ISC_TRUE; + strncpy(lookup->textname, rv[0], + sizeof(lookup->textname)); + lookup->textname[sizeof(lookup->textname)-1]=0; + lookup->trace_root = ISC_TF(lookup->trace || + lookup->ns_search_only); + lookup->new_search = ISC_TRUE; + if (firstarg) { + printgreeting(argc, argv, lookup); + firstarg = ISC_FALSE; + } + ISC_LIST_APPEND(lookup_list, lookup, link); + debug("looking up %s", lookup->textname); + } + /* XXX Error message */ + } + } + + /* + * If we have a batchfile, seed the lookup list with the + * first entry, then trust the callback in dighost_shutdown + * to get the rest + */ + if ((batchname != NULL) && !(is_batchfile)) { + if (strcmp(batchname, "-") == 0) + batchfp = stdin; + else + batchfp = fopen(batchname, "r"); + if (batchfp == NULL) { + perror(batchname); + if (exitcode < 8) + exitcode = 8; + fatal("couldn't open specified batch file"); + } + /* XXX Remove code dup from shutdown code */ + next_line: + if (fgets(batchline, sizeof(batchline), batchfp) != 0) { + bargc = 1; + debug("batch line %s", batchline); + if (batchline[0] == '\r' || batchline[0] == '\n' + || batchline[0] == '#' || batchline[0] == ';') + goto next_line; + input = batchline; + bargv[bargc] = next_token(&input, " \t\r\n"); + while ((bargv[bargc] != NULL) && (bargc < 14)) { + bargc++; + bargv[bargc] = next_token(&input, " \t\r\n"); + } + + bargv[0] = argv[0]; + argv0 = argv[0]; + + for(i = 0; i < bargc; i++) + debug("batch argv %d: %s", i, bargv[i]); + parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv); + return; + } + return; + } + /* + * If no lookup specified, search for root + */ + if ((lookup_list.head == NULL) && !config_only) { + if (need_clone) + lookup = clone_lookup(default_lookup, ISC_TRUE); + need_clone = ISC_TRUE; + lookup->trace_root = ISC_TF(lookup->trace || + lookup->ns_search_only); + lookup->new_search = ISC_TRUE; + strcpy(lookup->textname, "."); + lookup->rdtype = dns_rdatatype_ns; + lookup->rdtypeset = ISC_TRUE; + if (firstarg) { + printgreeting(argc, argv, lookup); + firstarg = ISC_FALSE; + } + ISC_LIST_APPEND(lookup_list, lookup, link); + } + if (!need_clone) + destroy_lookup(lookup); +} + +/* + * Callback from dighost.c to allow program-specific shutdown code. + * Here, we're possibly reading from a batch file, then shutting down + * for real if there's nothing in the batch file to read. + */ +void +dighost_shutdown(void) { + char batchline[MXNAME]; + int bargc; + char *bargv[16]; + char *input; + int i; + + if (batchname == NULL) { + isc_app_shutdown(); + return; + } + + fflush(stdout); + if (feof(batchfp)) { + batchname = NULL; + isc_app_shutdown(); + if (batchfp != stdin) + fclose(batchfp); + return; + } + + if (fgets(batchline, sizeof(batchline), batchfp) != 0) { + debug("batch line %s", batchline); + bargc = 1; + input = batchline; + bargv[bargc] = next_token(&input, " \t\r\n"); + while ((bargv[bargc] != NULL) && (bargc < 14)) { + bargc++; + bargv[bargc] = next_token(&input, " \t\r\n"); + } + + bargv[0] = argv0; + + for(i = 0; i < bargc; i++) + debug("batch argv %d: %s", i, bargv[i]); + parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv); + start_lookup(); + } else { + batchname = NULL; + if (batchfp != stdin) + fclose(batchfp); + isc_app_shutdown(); + return; + } +} + +/*% Main processing routine for dig */ +int +main(int argc, char **argv) { + isc_result_t result; + + ISC_LIST_INIT(lookup_list); + ISC_LIST_INIT(server_list); + ISC_LIST_INIT(search_list); + + debug("main()"); + preparse_args(argc, argv); + progname = argv[0]; + result = isc_app_start(); + check_result(result, "isc_app_start"); + setup_libs(); + parse_args(ISC_FALSE, ISC_FALSE, argc, argv); + setup_system(); + if (domainopt[0] != '\0') { + set_search_domain(domainopt); + usesearch = ISC_TRUE; + } + result = isc_app_onrun(mctx, global_task, onrun_callback, NULL); + check_result(result, "isc_app_onrun"); + isc_app_run(); + destroy_lookup(default_lookup); + if (batchname != NULL) { + if (batchfp != stdin) + fclose(batchfp); + batchname = NULL; + } +#ifdef DIG_SIGCHASE + clean_trustedkey(); +#endif + cancel_all(); + destroy_libs(); + isc_app_finish(); + return (exitcode); +} diff --git a/contrib/bind-9.5.2/bin/dig/dig.html b/contrib/bind-9.5.2/bin/dig/dig.html new file mode 100644 index 0000000000..13e1010541 --- /dev/null +++ b/contrib/bind-9.5.2/bin/dig/dig.html @@ -0,0 +1,639 @@ + + + + + +dig + + +
+
+
+

Name

+

dig — DNS lookup utility

+
+
+

Synopsis

+

dig [@server] [-b address] [-c class] [-f filename] [-k filename] [-m] [-p port#] [-q name] [-t type] [-x addr] [-y [hmac:]name:key] [-4] [-6] [name] [type] [class] [queryopt...]

+

dig [-h]

+

dig [global-queryopt...] [query...]

+
+
+

DESCRIPTION

+

dig + (domain information groper) is a flexible tool + for interrogating DNS name servers. It performs DNS lookups and + displays the answers that are returned from the name server(s) that + were queried. Most DNS administrators use dig to + troubleshoot DNS problems because of its flexibility, ease of use and + clarity of output. Other lookup tools tend to have less functionality + than dig. +

+

+ Although dig is normally used with + command-line + arguments, it also has a batch mode of operation for reading lookup + requests from a file. A brief summary of its command-line arguments + and options is printed when the -h option is given. + Unlike earlier versions, the BIND 9 implementation of + dig allows multiple lookups to be issued + from the + command line. +

+

+ Unless it is told to query a specific name server, + dig will try each of the servers listed + in + /etc/resolv.conf. +

+

+ When no command line arguments or options are given, + dig will perform an NS query for "." (the root). +

+

+ It is possible to set per-user defaults for dig via + ${HOME}/.digrc. This file is read and + any options in it + are applied before the command line arguments. +

+

+ The IN and CH class names overlap with the IN and CH top level + domains names. Either use the -t and + -c options to specify the type and class, + use the -q the specify the domain name, or + use "IN." and "CH." when looking up these top level domains. +

+
+
+

SIMPLE USAGE

+

+ A typical invocation of dig looks like: +

+
 dig @server name type 
+

+ where: + +

+
+
server
+

+ is the name or IP address of the name server to query. This can + be an IPv4 + address in dotted-decimal notation or an IPv6 + address in colon-delimited notation. When the supplied + server argument is a + hostname, + dig resolves that name before + querying that name + server. If no server + argument is provided, + dig consults /etc/resolv.conf + and queries the name servers listed there. The reply from the + name + server that responds is displayed. +

+
name
+

+ is the name of the resource record that is to be looked up. +

+
type
+

+ indicates what type of query is required — + ANY, A, MX, SIG, etc. + type can be any valid query + type. If no + type argument is supplied, + dig will perform a lookup for an + A record. +

+
+

+

+
+
+

OPTIONS

+

+ The -b option sets the source IP address of the query + to address. This must be a valid + address on + one of the host's network interfaces or "0.0.0.0" or "::". An optional + port + may be specified by appending "#<port>" +

+

+ The default query class (IN for internet) is overridden by the + -c option. class is + any valid + class, such as HS for Hesiod records or CH for Chaosnet records. +

+

+ The -f option makes dig + operate + in batch mode by reading a list of lookup requests to process from the + file filename. The file contains a + number of + queries, one per line. Each entry in the file should be organized in + the same way they would be presented as queries to + dig using the command-line interface. +

+

+ The -m option enables memory usage debugging. + +

+

+ If a non-standard port number is to be queried, the + -p option is used. port# is + the port number that dig will send its + queries + instead of the standard DNS port number 53. This option would be used + to test a name server that has been configured to listen for queries + on a non-standard port number. +

+

+ The -4 option forces dig + to only + use IPv4 query transport. The -6 option forces + dig to only use IPv6 query transport. +

+

+ The -t option sets the query type to + type. It can be any valid query type + which is + supported in BIND 9. The default query type is "A", unless the + -x option is supplied to indicate a reverse lookup. + A zone transfer can be requested by specifying a type of AXFR. When + an incremental zone transfer (IXFR) is required, + type is set to ixfr=N. + The incremental zone transfer will contain the changes made to the zone + since the serial number in the zone's SOA record was + N. +

+

+ The -q option sets the query name to + name. This useful do distinguish the + name from other arguments. +

+

+ Reverse lookups — mapping addresses to names — are simplified by the + -x option. addr is + an IPv4 + address in dotted-decimal notation, or a colon-delimited IPv6 address. + When this option is used, there is no need to provide the + name, class and + type arguments. dig + automatically performs a lookup for a name like + 11.12.13.10.in-addr.arpa and sets the + query type and + class to PTR and IN respectively. By default, IPv6 addresses are + looked up using nibble format under the IP6.ARPA domain. + To use the older RFC1886 method using the IP6.INT domain + specify the -i option. Bit string labels (RFC2874) + are now experimental and are not attempted. +

+

+ To sign the DNS queries sent by dig and + their + responses using transaction signatures (TSIG), specify a TSIG key file + using the -k option. You can also specify the TSIG + key itself on the command line using the -y option; + hmac is the type of the TSIG, default HMAC-MD5, + name is the name of the TSIG key and + key is the actual key. The key is a + base-64 + encoded string, typically generated by + dnssec-keygen(8). + + Caution should be taken when using the -y option on + multi-user systems as the key can be visible in the output from + ps(1) + or in the shell's history file. When + using TSIG authentication with dig, the name + server that is queried needs to know the key and algorithm that is + being used. In BIND, this is done by providing appropriate + key and server statements in + named.conf. +

+
+
+

QUERY OPTIONS

+

dig + provides a number of query options which affect + the way in which lookups are made and the results displayed. Some of + these set or reset flag bits in the query header, some determine which + sections of the answer get printed, and others determine the timeout + and retry strategies. +

+

+ Each query option is identified by a keyword preceded by a plus sign + (+). Some keywords set or reset an + option. These may be preceded + by the string no to negate the meaning of + that keyword. Other + keywords assign values to options like the timeout interval. They + have the form +keyword=value. + The query options are: + +

+
+
+[no]tcp
+

+ Use [do not use] TCP when querying name servers. The default + behavior is to use UDP unless an AXFR or IXFR query is + requested, in + which case a TCP connection is used. +

+
+[no]vc
+

+ Use [do not use] TCP when querying name servers. This alternate + syntax to +[no]tcp is + provided for backwards + compatibility. The "vc" stands for "virtual circuit". +

+
+[no]ignore
+

+ Ignore truncation in UDP responses instead of retrying with TCP. + By + default, TCP retries are performed. +

+
+domain=somename
+

+ Set the search list to contain the single domain + somename, as if specified in + a + domain directive in + /etc/resolv.conf, and enable + search list + processing as if the +search + option were given. +

+
+[no]search
+

+ Use [do not use] the search list defined by the searchlist or + domain + directive in resolv.conf (if + any). + The search list is not used by default. +

+
+[no]showsearch
+

+ Perform [do not perform] a search showing intermediate + results. +

+
+[no]defname
+

+ Deprecated, treated as a synonym for +[no]search +

+
+[no]aaonly
+

+ Sets the "aa" flag in the query. +

+
+[no]aaflag
+

+ A synonym for +[no]aaonly. +

+
+[no]adflag
+

+ Set [do not set] the AD (authentic data) bit in the + query. This requests the server to return whether + all of the answer and authority sections have all + been validated as secure according to the security + policy of the server. AD=1 indicates that all records + have been validated as secure and the answer is not + from a OPT-OUT range. AD=0 indicate that some part + of the answer was insecure or not validated. +

+
+[no]cdflag
+

+ Set [do not set] the CD (checking disabled) bit in the query. + This + requests the server to not perform DNSSEC validation of + responses. +

+
+[no]cl
+

+ Display [do not display] the CLASS when printing the record. +

+
+[no]ttlid
+

+ Display [do not display] the TTL when printing the record. +

+
+[no]recurse
+

+ Toggle the setting of the RD (recursion desired) bit in the + query. + This bit is set by default, which means dig + normally sends recursive queries. Recursion is automatically + disabled + when the +nssearch or + +trace query options are + used. +

+
+[no]nssearch
+

+ When this option is set, dig + attempts to find the + authoritative name servers for the zone containing the name + being + looked up and display the SOA record that each name server has + for the + zone. +

+
+[no]trace
+

+ Toggle tracing of the delegation path from the root name servers + for + the name being looked up. Tracing is disabled by default. When + tracing is enabled, dig makes + iterative queries to + resolve the name being looked up. It will follow referrals from + the + root servers, showing the answer from each server that was used + to + resolve the lookup. +

+
+[no]cmd
+

+ Toggles the printing of the initial comment in the output + identifying + the version of dig and the query + options that have + been applied. This comment is printed by default. +

+
+[no]short
+

+ Provide a terse answer. The default is to print the answer in a + verbose form. +

+
+[no]identify
+

+ Show [or do not show] the IP address and port number that + supplied the + answer when the +short option + is enabled. If + short form answers are requested, the default is not to show the + source address and port number of the server that provided the + answer. +

+
+[no]comments
+

+ Toggle the display of comment lines in the output. The default + is to + print comments. +

+
+[no]stats
+

+ This query option toggles the printing of statistics: when the + query + was made, the size of the reply and so on. The default + behavior is + to print the query statistics. +

+
+[no]qr
+

+ Print [do not print] the query as it is sent. + By default, the query is not printed. +

+
+[no]question
+

+ Print [do not print] the question section of a query when an + answer is + returned. The default is to print the question section as a + comment. +

+
+[no]answer
+

+ Display [do not display] the answer section of a reply. The + default + is to display it. +

+
+[no]authority
+

+ Display [do not display] the authority section of a reply. The + default is to display it. +

+
+[no]additional
+

+ Display [do not display] the additional section of a reply. + The default is to display it. +

+
+[no]all
+

+ Set or clear all display flags. +

+
+time=T
+

+ + Sets the timeout for a query to + T seconds. The default + timeout is 5 seconds. + An attempt to set T to less + than 1 will result + in a query timeout of 1 second being applied. +

+
+tries=T
+

+ Sets the number of times to try UDP queries to server to + T instead of the default, 3. + If + T is less than or equal to + zero, the number of + tries is silently rounded up to 1. +

+
+retry=T
+

+ Sets the number of times to retry UDP queries to server to + T instead of the default, 2. + Unlike + +tries, this does not include + the initial + query. +

+
+ndots=D
+

+ Set the number of dots that have to appear in + name to D for it to be + considered absolute. The default value is that defined using + the + ndots statement in /etc/resolv.conf, or 1 if no + ndots statement is present. Names with fewer dots are + interpreted as + relative names and will be searched for in the domains listed in + the + search or domain directive in + /etc/resolv.conf. +

+
+bufsize=B
+

+ Set the UDP message buffer size advertised using EDNS0 to + B bytes. The maximum and minimum sizes + of this buffer are 65535 and 0 respectively. Values outside + this range are rounded up or down appropriately. + Values other than zero will cause a EDNS query to be sent. +

+
+edns=#
+

+ Specify the EDNS version to query with. Valid values + are 0 to 255. Setting the EDNS version will cause a + EDNS query to be sent. +noedns clears the + remembered EDNS version. +

+
+[no]multiline
+

+ Print records like the SOA records in a verbose multi-line + format with human-readable comments. The default is to print + each record on a single line, to facilitate machine parsing + of the dig output. +

+
+[no]fail
+

+ Do not try the next server if you receive a SERVFAIL. The + default is + to not try the next server which is the reverse of normal stub + resolver + behavior. +

+
+[no]besteffort
+

+ Attempt to display the contents of messages which are malformed. + The default is to not display malformed answers. +

+
+[no]dnssec
+

+ Requests DNSSEC records be sent by setting the DNSSEC OK bit + (DO) + in the OPT record in the additional section of the query. +

+
+[no]sigchase
+

+ Chase DNSSEC signature chains. Requires dig be compiled with + -DDIG_SIGCHASE. +

+
+trusted-key=####
+
+

+ Specifies a file containing trusted keys to be used with + +sigchase. Each DNSKEY record must be + on its own line. +

+

+ If not specified, dig will look for + /etc/trusted-key.key then + trusted-key.key in the current directory. +

+

+ Requires dig be compiled with -DDIG_SIGCHASE. +

+
+
+[no]topdown
+

+ When chasing DNSSEC signature chains perform a top-down + validation. + Requires dig be compiled with -DDIG_SIGCHASE. +

+
+[no]nsid
+

+ Include an EDNS name server ID request when sending a query. +

+
+

+ +

+
+
+

MULTIPLE QUERIES

+

+ The BIND 9 implementation of dig + supports + specifying multiple queries on the command line (in addition to + supporting the -f batch file option). Each of those + queries can be supplied with its own set of flags, options and query + options. +

+

+ In this case, each query argument + represent an + individual query in the command-line syntax described above. Each + consists of any of the standard options and flags, the name to be + looked up, an optional query type and class and any query options that + should be applied to that query. +

+

+ A global set of query options, which should be applied to all queries, + can also be supplied. These global query options must precede the + first tuple of name, class, type, options, flags, and query options + supplied on the command line. Any global query options (except + the +[no]cmd option) can be + overridden by a query-specific set of query options. For example: +

+
+dig +qr www.isc.org any -x 127.0.0.1 isc.org ns +noqr
+
+

+ shows how dig could be used from the + command line + to make three lookups: an ANY query for www.isc.org, a + reverse lookup of 127.0.0.1 and a query for the NS records of + isc.org. + + A global query option of +qr is + applied, so + that dig shows the initial query it made + for each + lookup. The final query has a local query option of + +noqr which means that dig + will not print the initial query when it looks up the NS records for + isc.org. +

+
+
+

IDN SUPPORT

+

+ If dig has been built with IDN (internationalized + domain name) support, it can accept and display non-ASCII domain names. + dig appropriately converts character encoding of + domain name before sending a request to DNS server or displaying a + reply from the server. + If you'd like to turn off the IDN support for some reason, defines + the IDN_DISABLE environment variable. + The IDN support is disabled if the variable is set when + dig runs. +

+
+
+

FILES

+

/etc/resolv.conf +

+

${HOME}/.digrc +

+
+
+

SEE ALSO

+

host(1), + named(8), + dnssec-keygen(8), + RFC1035. +

+
+
+

BUGS

+

+ There are probably too many query options. +

+
+
+ diff --git a/contrib/bind-9.5.2/bin/dig/dighost.c b/contrib/bind-9.5.2/bin/dig/dighost.c new file mode 100644 index 0000000000..09c2cdafdd --- /dev/null +++ b/contrib/bind-9.5.2/bin/dig/dighost.c @@ -0,0 +1,5522 @@ +/* + * 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 + * 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: dighost.c,v 1.304.12.16 2009/06/24 03:42:32 marka Exp $ */ + +/*! \file + * \note + * Notice to programmers: Do not use this code as an example of how to + * use the ISC library to perform DNS lookups. Dig and Host both operate + * on the request level, since they allow fine-tuning of output and are + * intended as debugging tools. As a result, they perform many of the + * functions which could be better handled using the dns_resolver + * functions in most applications. + */ + +#include +#include +#include +#include +#include + +#ifdef HAVE_LOCALE_H +#include +#endif + +#ifdef WITH_IDN +#include +#include +#include +#include +#endif + +#include +#ifdef DIG_SIGCHASE +#include +#include +#include +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#ifdef DIG_SIGCHASE +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#if ! defined(NS_INADDRSZ) +#define NS_INADDRSZ 4 +#endif + +#if ! defined(NS_IN6ADDRSZ) +#define NS_IN6ADDRSZ 16 +#endif + +static lwres_context_t *lwctx = NULL; +static lwres_conf_t *lwconf; + +dig_lookuplist_t lookup_list; +dig_serverlist_t server_list; +dig_searchlistlist_t search_list; + +isc_boolean_t + check_ra = ISC_FALSE, + have_ipv4 = ISC_FALSE, + have_ipv6 = ISC_FALSE, + specified_source = ISC_FALSE, + free_now = ISC_FALSE, + cancel_now = ISC_FALSE, + usesearch = ISC_FALSE, + showsearch = ISC_FALSE, + qr = ISC_FALSE, + is_dst_up = ISC_FALSE; +in_port_t port = 53; +unsigned int timeout = 0; +unsigned int extrabytes; +isc_mem_t *mctx = NULL; +isc_taskmgr_t *taskmgr = NULL; +isc_task_t *global_task = NULL; +isc_timermgr_t *timermgr = NULL; +isc_socketmgr_t *socketmgr = NULL; +isc_sockaddr_t bind_address; +isc_sockaddr_t bind_any; +int sendcount = 0; +int recvcount = 0; +int sockcount = 0; +int ndots = -1; +int tries = 3; +int lookup_counter = 0; + +#ifdef WITH_IDN +static void initialize_idn(void); +static isc_result_t output_filter(isc_buffer_t *buffer, + unsigned int used_org, + isc_boolean_t absolute); +static idn_result_t append_textname(char *name, const char *origin, + size_t namesize); +static void idn_check_result(idn_result_t r, const char *msg); + +#define MAXDLEN 256 +int idnoptions = 0; +#endif + +/*% + * Exit Codes: + * + *\li 0 Everything went well, including things like NXDOMAIN + *\li 1 Usage error + *\li 7 Got too many RR's or Names + *\li 8 Couldn't open batch file + *\li 9 No reply from server + *\li 10 Internal error + */ +int exitcode = 0; +int fatalexit = 0; +char keynametext[MXNAME]; +char keyfile[MXNAME] = ""; +char keysecret[MXNAME] = ""; +dns_name_t *hmacname = NULL; +unsigned int digestbits = 0; +isc_buffer_t *namebuf = NULL; +dns_tsigkey_t *key = NULL; +isc_boolean_t validated = ISC_TRUE; +isc_entropy_t *entp = NULL; +isc_mempool_t *commctx = NULL; +isc_boolean_t debugging = ISC_FALSE; +isc_boolean_t memdebugging = ISC_FALSE; +char *progname = NULL; +isc_mutex_t lookup_lock; +dig_lookup_t *current_lookup = NULL; + +#ifdef DIG_SIGCHASE + +isc_result_t get_trusted_key(isc_mem_t *mctx); +dns_rdataset_t * sigchase_scanname(dns_rdatatype_t type, + dns_rdatatype_t covers, + isc_boolean_t *lookedup, + dns_name_t *rdata_name); +dns_rdataset_t * chase_scanname_section(dns_message_t *msg, + dns_name_t *name, + dns_rdatatype_t type, + dns_rdatatype_t covers, + int section); +isc_result_t advanced_rrsearch(dns_rdataset_t **rdataset, + dns_name_t *name, + dns_rdatatype_t type, + dns_rdatatype_t covers, + isc_boolean_t *lookedup); +isc_result_t sigchase_verify_sig_key(dns_name_t *name, + dns_rdataset_t *rdataset, + dst_key_t* dnsseckey, + dns_rdataset_t *sigrdataset, + isc_mem_t *mctx); +isc_result_t sigchase_verify_sig(dns_name_t *name, + dns_rdataset_t *rdataset, + dns_rdataset_t *keyrdataset, + dns_rdataset_t *sigrdataset, + isc_mem_t *mctx); +isc_result_t sigchase_verify_ds(dns_name_t *name, + dns_rdataset_t *keyrdataset, + dns_rdataset_t *dsrdataset, + isc_mem_t *mctx); +void sigchase(dns_message_t *msg); +void print_rdata(dns_rdata_t *rdata, isc_mem_t *mctx); +void print_rdataset(dns_name_t *name, + dns_rdataset_t *rdataset, isc_mem_t *mctx); +void dup_name(dns_name_t *source, dns_name_t* target, + isc_mem_t *mctx); +void free_name(dns_name_t *name, isc_mem_t *mctx); +void dump_database(void); +void dump_database_section(dns_message_t *msg, int section); +dns_rdataset_t * search_type(dns_name_t *name, dns_rdatatype_t type, + dns_rdatatype_t covers); +isc_result_t contains_trusted_key(dns_name_t *name, + dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset, + isc_mem_t *mctx); +void print_type(dns_rdatatype_t type); +isc_result_t prove_nx_domain(dns_message_t * msg, + dns_name_t * name, + dns_name_t * rdata_name, + dns_rdataset_t ** rdataset, + dns_rdataset_t ** sigrdataset); +isc_result_t prove_nx_type(dns_message_t * msg, dns_name_t *name, + dns_rdataset_t *nsec, + dns_rdataclass_t class, + dns_rdatatype_t type, + dns_name_t * rdata_name, + dns_rdataset_t ** rdataset, + dns_rdataset_t ** sigrdataset); +isc_result_t prove_nx(dns_message_t * msg, dns_name_t * name, + dns_rdataclass_t class, + dns_rdatatype_t type, + dns_name_t * rdata_name, + dns_rdataset_t ** rdataset, + dns_rdataset_t ** sigrdataset); +static void nameFromString(const char *str, dns_name_t *p_ret); +int inf_name(dns_name_t * name1, dns_name_t * name2); +isc_result_t opentmpkey(isc_mem_t *mctx, const char *file, + char **tempp, FILE **fp); +isc_result_t removetmpkey(isc_mem_t *mctx, const char *file); +void clean_trustedkey(void); +void insert_trustedkey(dst_key_t * key); +#if DIG_SIGCHASE_BU +isc_result_t getneededrr(dns_message_t *msg); +void sigchase_bottom_up(dns_message_t *msg); +void sigchase_bu(dns_message_t *msg); +#endif +#if DIG_SIGCHASE_TD +isc_result_t initialization(dns_name_t *name); +isc_result_t prepare_lookup(dns_name_t *name); +isc_result_t grandfather_pb_test(dns_name_t * zone_name, + dns_rdataset_t *sigrdataset); +isc_result_t child_of_zone(dns_name_t *name, + dns_name_t *zone_name, + dns_name_t *child_name); +void sigchase_td(dns_message_t *msg); +#endif +char trustedkey[MXNAME] = ""; + +dns_rdataset_t *chase_rdataset = NULL; +dns_rdataset_t *chase_sigrdataset = NULL; +dns_rdataset_t *chase_dsrdataset = NULL; +dns_rdataset_t *chase_sigdsrdataset = NULL; +dns_rdataset_t *chase_keyrdataset = NULL; +dns_rdataset_t *chase_sigkeyrdataset = NULL; +dns_rdataset_t *chase_nsrdataset = NULL; + +dns_name_t chase_name; /* the query name */ +#if DIG_SIGCHASE_TD +/* + * the current name is the parent name when we follow delegation + */ +dns_name_t chase_current_name; +/* + * the child name is used for delegation (NS DS responses in AUTHORITY section) + */ +dns_name_t chase_authority_name; +#endif +#if DIG_SIGCHASE_BU +dns_name_t chase_signame; +#endif + + +isc_boolean_t chase_siglookedup = ISC_FALSE; +isc_boolean_t chase_keylookedup = ISC_FALSE; +isc_boolean_t chase_sigkeylookedup = ISC_FALSE; +isc_boolean_t chase_dslookedup = ISC_FALSE; +isc_boolean_t chase_sigdslookedup = ISC_FALSE; +#if DIG_SIGCHASE_TD +isc_boolean_t chase_nslookedup = ISC_FALSE; +isc_boolean_t chase_lookedup = ISC_FALSE; + + +isc_boolean_t delegation_follow = ISC_FALSE; +isc_boolean_t grandfather_pb = ISC_FALSE; +isc_boolean_t have_response = ISC_FALSE; +isc_boolean_t have_delegation_ns = ISC_FALSE; +dns_message_t * error_message = NULL; +#endif + +isc_boolean_t dsvalidating = ISC_FALSE; +isc_boolean_t chase_name_dup = ISC_FALSE; + +ISC_LIST(dig_message_t) chase_message_list; +ISC_LIST(dig_message_t) chase_message_list2; + + +#define MAX_TRUSTED_KEY 5 +typedef struct struct_trusted_key_list { + dst_key_t * key[MAX_TRUSTED_KEY]; + int nb_tk; +} struct_tk_list; + +struct_tk_list tk_list = { {NULL, NULL, NULL, NULL, NULL}, 0}; + +#endif + +#define DIG_MAX_ADDRESSES 20 + +/*% + * Apply and clear locks at the event level in global task. + * Can I get rid of these using shutdown events? XXX + */ +#define LOCK_LOOKUP {\ + debug("lock_lookup %s:%d", __FILE__, __LINE__);\ + check_result(isc_mutex_lock((&lookup_lock)), "isc_mutex_lock");\ + debug("success");\ +} +#define UNLOCK_LOOKUP {\ + debug("unlock_lookup %s:%d", __FILE__, __LINE__);\ + check_result(isc_mutex_unlock((&lookup_lock)),\ + "isc_mutex_unlock");\ +} + +static void +cancel_lookup(dig_lookup_t *lookup); + +static void +recv_done(isc_task_t *task, isc_event_t *event); + +static void +send_udp(dig_query_t *query); + +static void +connect_timeout(isc_task_t *task, isc_event_t *event); + +static void +launch_next_query(dig_query_t *query, isc_boolean_t include_question); + + +static void * +mem_alloc(void *arg, size_t size) { + return (isc_mem_get(arg, size)); +} + +static void +mem_free(void *arg, void *mem, size_t size) { + isc_mem_put(arg, mem, size); +} + +char * +next_token(char **stringp, const char *delim) { + char *res; + + do { + res = strsep(stringp, delim); + if (res == NULL) + break; + } while (*res == '\0'); + return (res); +} + +static int +count_dots(char *string) { + char *s; + int i = 0; + + s = string; + while (*s != '\0') { + if (*s == '.') + i++; + s++; + } + return (i); +} + +static void +hex_dump(isc_buffer_t *b) { + unsigned int len; + isc_region_t r; + + isc_buffer_usedregion(b, &r); + + printf("%d bytes\n", r.length); + for (len = 0; len < r.length; len++) { + printf("%02x ", r.base[len]); + if (len % 16 == 15) + printf("\n"); + } + if (len % 16 != 0) + printf("\n"); +} + +/*% + * Append 'len' bytes of 'text' at '*p', failing with + * ISC_R_NOSPACE if that would advance p past 'end'. + */ +static isc_result_t +append(const char *text, int len, char **p, char *end) { + if (len > end - *p) + return (ISC_R_NOSPACE); + memcpy(*p, text, len); + *p += len; + return (ISC_R_SUCCESS); +} + +static isc_result_t +reverse_octets(const char *in, char **p, char *end) { + char *dot = strchr(in, '.'); + int len; + if (dot != NULL) { + isc_result_t result; + result = reverse_octets(dot + 1, p, end); + if (result != ISC_R_SUCCESS) + return (result); + result = append(".", 1, p, end); + if (result != ISC_R_SUCCESS) + return (result); + len = dot - in; + } else { + len = strlen(in); + } + return (append(in, len, p, end)); +} + +isc_result_t +get_reverse(char *reverse, size_t len, char *value, isc_boolean_t ip6_int, + isc_boolean_t strict) +{ + int r; + isc_result_t result; + isc_netaddr_t addr; + + addr.family = AF_INET6; + r = inet_pton(AF_INET6, value, &addr.type.in6); + if (r > 0) { + /* This is a valid IPv6 address. */ + dns_fixedname_t fname; + dns_name_t *name; + unsigned int options = 0; + + if (ip6_int) + options |= DNS_BYADDROPT_IPV6INT; + dns_fixedname_init(&fname); + name = dns_fixedname_name(&fname); + result = dns_byaddr_createptrname2(&addr, options, name); + if (result != ISC_R_SUCCESS) + return (result); + dns_name_format(name, reverse, len); + return (ISC_R_SUCCESS); + } else { + /* + * Not a valid IPv6 address. Assume IPv4. + * If 'strict' is not set, construct the + * in-addr.arpa name by blindly reversing + * octets whether or not they look like integers, + * so that this can be used for RFC2317 names + * and such. + */ + char *p = reverse; + char *end = reverse + len; + if (strict && inet_pton(AF_INET, value, &addr.type.in) != 1) + return (DNS_R_BADDOTTEDQUAD); + result = reverse_octets(value, &p, end); + if (result != ISC_R_SUCCESS) + return (result); + /* Append .in-addr.arpa. and a terminating NUL. */ + result = append(".in-addr.arpa.", 15, &p, end); + if (result != ISC_R_SUCCESS) + return (result); + return (ISC_R_SUCCESS); + } +} + +void +fatal(const char *format, ...) { + va_list args; + + fflush(stdout); + fprintf(stderr, "%s: ", progname); + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + if (exitcode < 10) + exitcode = 10; + if (fatalexit != 0) + exitcode = fatalexit; + exit(exitcode); +} + +void +debug(const char *format, ...) { + va_list args; + + if (debugging) { + fflush(stdout); + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + } +} + +void +check_result(isc_result_t result, const char *msg) { + if (result != ISC_R_SUCCESS) { + fatal("%s: %s", msg, isc_result_totext(result)); + } +} + +/*% + * Create a server structure, which is part of the lookup structure. + * This is little more than a linked list of servers to query in hopes + * of finding the answer the user is looking for + */ +dig_server_t * +make_server(const char *servname, const char *userarg) { + dig_server_t *srv; + + REQUIRE(servname != NULL); + + debug("make_server(%s)", servname); + srv = isc_mem_allocate(mctx, sizeof(struct dig_server)); + if (srv == NULL) + fatal("memory allocation failure in %s:%d", + __FILE__, __LINE__); + strncpy(srv->servername, servname, MXNAME); + strncpy(srv->userarg, userarg, MXNAME); + srv->servername[MXNAME-1] = 0; + srv->userarg[MXNAME-1] = 0; + ISC_LINK_INIT(srv, link); + return (srv); +} + +static int +addr2af(int lwresaddrtype) +{ + int af = 0; + + switch (lwresaddrtype) { + case LWRES_ADDRTYPE_V4: + af = AF_INET; + break; + + case LWRES_ADDRTYPE_V6: + af = AF_INET6; + break; + } + + return (af); +} + +/*% + * Create a copy of the server list from the lwres configuration structure. + * The dest list must have already had ISC_LIST_INIT applied. + */ +static void +copy_server_list(lwres_conf_t *confdata, dig_serverlist_t *dest) { + dig_server_t *newsrv; + char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; + int af; + int i; + + debug("copy_server_list()"); + for (i = 0; i < confdata->nsnext; i++) { + af = addr2af(confdata->nameservers[i].family); + + if (af == AF_INET && !have_ipv4) + continue; + if (af == AF_INET6 && !have_ipv6) + continue; + + lwres_net_ntop(af, confdata->nameservers[i].address, + tmp, sizeof(tmp)); + newsrv = make_server(tmp, tmp); + ISC_LINK_INIT(newsrv, link); + ISC_LIST_ENQUEUE(*dest, newsrv, link); + } +} + +void +flush_server_list(void) { + dig_server_t *s, *ps; + + debug("flush_server_list()"); + s = ISC_LIST_HEAD(server_list); + while (s != NULL) { + ps = s; + s = ISC_LIST_NEXT(s, link); + ISC_LIST_DEQUEUE(server_list, ps, link); + isc_mem_free(mctx, ps); + } +} + +void +set_nameserver(char *opt) { + isc_result_t result; + isc_sockaddr_t sockaddrs[DIG_MAX_ADDRESSES]; + isc_netaddr_t netaddr; + int count, i; + dig_server_t *srv; + char tmp[ISC_NETADDR_FORMATSIZE]; + + if (opt == NULL) + return; + + result = bind9_getaddresses(opt, 0, sockaddrs, + DIG_MAX_ADDRESSES, &count); + if (result != ISC_R_SUCCESS) + fatal("couldn't get address for '%s': %s", + opt, isc_result_totext(result)); + + flush_server_list(); + + for (i = 0; i < count; i++) { + isc_netaddr_fromsockaddr(&netaddr, &sockaddrs[i]); + isc_netaddr_format(&netaddr, tmp, sizeof(tmp)); + srv = make_server(tmp, opt); + if (srv == NULL) + fatal("memory allocation failure"); + ISC_LIST_APPEND(server_list, srv, link); + } +} + +static isc_result_t +add_nameserver(lwres_conf_t *confdata, const char *addr, int af) { + + int i = confdata->nsnext; + + if (confdata->nsnext >= LWRES_CONFMAXNAMESERVERS) + return (ISC_R_FAILURE); + + switch (af) { + case AF_INET: + confdata->nameservers[i].family = LWRES_ADDRTYPE_V4; + confdata->nameservers[i].length = NS_INADDRSZ; + break; + case AF_INET6: + confdata->nameservers[i].family = LWRES_ADDRTYPE_V6; + confdata->nameservers[i].length = NS_IN6ADDRSZ; + break; + default: + return (ISC_R_FAILURE); + } + + if (lwres_net_pton(af, addr, &confdata->nameservers[i].address) == 1) { + confdata->nsnext++; + return (ISC_R_SUCCESS); + } + return (ISC_R_FAILURE); +} + +/*% + * Produce a cloned server list. The dest list must have already had + * ISC_LIST_INIT applied. + */ +void +clone_server_list(dig_serverlist_t src, dig_serverlist_t *dest) { + dig_server_t *srv, *newsrv; + + debug("clone_server_list()"); + srv = ISC_LIST_HEAD(src); + while (srv != NULL) { + newsrv = make_server(srv->servername, srv->userarg); + ISC_LINK_INIT(newsrv, link); + ISC_LIST_ENQUEUE(*dest, newsrv, link); + srv = ISC_LIST_NEXT(srv, link); + } +} + +/*% + * Create an empty lookup structure, which holds all the information needed + * to get an answer to a user's question. This structure contains two + * linked lists: the server list (servers to query) and the query list + * (outstanding queries which have been made to the listed servers). + */ +dig_lookup_t * +make_empty_lookup(void) { + dig_lookup_t *looknew; + + debug("make_empty_lookup()"); + + INSIST(!free_now); + + looknew = isc_mem_allocate(mctx, sizeof(struct dig_lookup)); + if (looknew == NULL) + fatal("memory allocation failure in %s:%d", + __FILE__, __LINE__); + looknew->pending = ISC_TRUE; + looknew->textname[0] = 0; + looknew->cmdline[0] = 0; + looknew->rdtype = dns_rdatatype_a; + looknew->qrdtype = dns_rdatatype_a; + looknew->rdclass = dns_rdataclass_in; + looknew->rdtypeset = ISC_FALSE; + looknew->rdclassset = ISC_FALSE; + looknew->sendspace = NULL; + looknew->sendmsg = NULL; + looknew->name = NULL; + looknew->oname = NULL; + looknew->timer = NULL; + looknew->xfr_q = NULL; + looknew->current_query = NULL; + looknew->doing_xfr = ISC_FALSE; + looknew->ixfr_serial = ISC_FALSE; + looknew->trace = ISC_FALSE; + looknew->trace_root = ISC_FALSE; + looknew->identify = ISC_FALSE; + looknew->identify_previous_line = ISC_FALSE; + looknew->ignore = ISC_FALSE; + looknew->servfail_stops = ISC_TRUE; + looknew->besteffort = ISC_TRUE; + looknew->dnssec = ISC_FALSE; + looknew->nsid = ISC_FALSE; +#ifdef DIG_SIGCHASE + looknew->sigchase = ISC_FALSE; +#if DIG_SIGCHASE_TD + looknew->do_topdown = ISC_FALSE; + looknew->trace_root_sigchase = ISC_FALSE; + looknew->rdtype_sigchaseset = ISC_FALSE; + looknew->rdtype_sigchase = dns_rdatatype_any; + looknew->qrdtype_sigchase = dns_rdatatype_any; + looknew->rdclass_sigchase = dns_rdataclass_in; + looknew->rdclass_sigchaseset = ISC_FALSE; +#endif +#endif + looknew->udpsize = 0; + looknew->edns = -1; + looknew->recurse = ISC_TRUE; + looknew->aaonly = ISC_FALSE; + looknew->adflag = ISC_FALSE; + looknew->cdflag = ISC_FALSE; + looknew->ns_search_only = ISC_FALSE; + looknew->origin = NULL; + looknew->tsigctx = NULL; + looknew->querysig = NULL; + looknew->retries = tries; + looknew->nsfound = 0; + looknew->tcp_mode = ISC_FALSE; + looknew->ip6_int = ISC_FALSE; + looknew->comments = ISC_TRUE; + looknew->stats = ISC_TRUE; + looknew->section_question = ISC_TRUE; + looknew->section_answer = ISC_TRUE; + looknew->section_authority = ISC_TRUE; + looknew->section_additional = ISC_TRUE; + looknew->new_search = ISC_FALSE; + looknew->done_as_is = ISC_FALSE; + looknew->need_search = ISC_FALSE; + ISC_LINK_INIT(looknew, link); + ISC_LIST_INIT(looknew->q); + ISC_LIST_INIT(looknew->my_server_list); + return (looknew); +} + +/*% + * Clone a lookup, perhaps copying the server list. This does not clone + * the query list, since it will be regenerated by the setup_lookup() + * function, nor does it queue up the new lookup for processing. + * Caution: If you don't clone the servers, you MUST clone the server + * list separately from somewhere else, or construct it by hand. + */ +dig_lookup_t * +clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers) { + dig_lookup_t *looknew; + + debug("clone_lookup()"); + + INSIST(!free_now); + + looknew = make_empty_lookup(); + INSIST(looknew != NULL); + strncpy(looknew->textname, lookold->textname, MXNAME); +#if DIG_SIGCHASE_TD + strncpy(looknew->textnamesigchase, lookold->textnamesigchase, MXNAME); +#endif + strncpy(looknew->cmdline, lookold->cmdline, MXNAME); + looknew->textname[MXNAME-1] = 0; + looknew->rdtype = lookold->rdtype; + looknew->qrdtype = lookold->qrdtype; + looknew->rdclass = lookold->rdclass; + looknew->rdtypeset = lookold->rdtypeset; + looknew->rdclassset = lookold->rdclassset; + looknew->doing_xfr = lookold->doing_xfr; + looknew->ixfr_serial = lookold->ixfr_serial; + looknew->trace = lookold->trace; + looknew->trace_root = lookold->trace_root; + looknew->identify = lookold->identify; + looknew->identify_previous_line = lookold->identify_previous_line; + looknew->ignore = lookold->ignore; + looknew->servfail_stops = lookold->servfail_stops; + looknew->besteffort = lookold->besteffort; + looknew->dnssec = lookold->dnssec; + looknew->nsid = lookold->nsid; +#ifdef DIG_SIGCHASE + looknew->sigchase = lookold->sigchase; +#if DIG_SIGCHASE_TD + looknew->do_topdown = lookold->do_topdown; + looknew->trace_root_sigchase = lookold->trace_root_sigchase; + looknew->rdtype_sigchaseset = lookold->rdtype_sigchaseset; + looknew->rdtype_sigchase = lookold->rdtype_sigchase; + looknew->qrdtype_sigchase = lookold->qrdtype_sigchase; + looknew->rdclass_sigchase = lookold->rdclass_sigchase; + looknew->rdclass_sigchaseset = lookold->rdclass_sigchaseset; +#endif +#endif + looknew->udpsize = lookold->udpsize; + looknew->edns = lookold->edns; + looknew->recurse = lookold->recurse; + looknew->aaonly = lookold->aaonly; + looknew->adflag = lookold->adflag; + looknew->cdflag = lookold->cdflag; + looknew->ns_search_only = lookold->ns_search_only; + looknew->tcp_mode = lookold->tcp_mode; + looknew->comments = lookold->comments; + looknew->stats = lookold->stats; + looknew->section_question = lookold->section_question; + looknew->section_answer = lookold->section_answer; + looknew->section_authority = lookold->section_authority; + looknew->section_additional = lookold->section_additional; + looknew->retries = lookold->retries; + looknew->tsigctx = NULL; + looknew->need_search = lookold->need_search; + looknew->done_as_is = lookold->done_as_is; + + if (servers) + clone_server_list(lookold->my_server_list, + &looknew->my_server_list); + return (looknew); +} + +/*% + * Requeue a lookup for further processing, perhaps copying the server + * list. The new lookup structure is returned to the caller, and is + * queued for processing. If servers are not cloned in the requeue, they + * must be added before allowing the current event to complete, since the + * completion of the event may result in the next entry on the lookup + * queue getting run. + */ +dig_lookup_t * +requeue_lookup(dig_lookup_t *lookold, isc_boolean_t servers) { + dig_lookup_t *looknew; + + debug("requeue_lookup()"); + + lookup_counter++; + if (lookup_counter > LOOKUP_LIMIT) + fatal("too many lookups"); + + looknew = clone_lookup(lookold, servers); + INSIST(looknew != NULL); + + debug("before insertion, init@%p -> %p, new@%p -> %p", + lookold, lookold->link.next, looknew, looknew->link.next); + ISC_LIST_PREPEND(lookup_list, looknew, link); + debug("after insertion, init -> %p, new = %p, new -> %p", + lookold, looknew, looknew->link.next); + return (looknew); +} + + +static void +setup_text_key(void) { + isc_result_t result; + dns_name_t keyname; + isc_buffer_t secretbuf; + int secretsize; + unsigned char *secretstore; + + debug("setup_text_key()"); + result = isc_buffer_allocate(mctx, &namebuf, MXNAME); + check_result(result, "isc_buffer_allocate"); + dns_name_init(&keyname, NULL); + check_result(result, "dns_name_init"); + isc_buffer_putstr(namebuf, keynametext); + secretsize = strlen(keysecret) * 3 / 4; + secretstore = isc_mem_allocate(mctx, secretsize); + if (secretstore == NULL) + fatal("memory allocation failure in %s:%d", + __FILE__, __LINE__); + isc_buffer_init(&secretbuf, secretstore, secretsize); + result = isc_base64_decodestring(keysecret, &secretbuf); + if (result != ISC_R_SUCCESS) + goto failure; + + secretsize = isc_buffer_usedlength(&secretbuf); + + result = dns_name_fromtext(&keyname, namebuf, + dns_rootname, ISC_FALSE, + namebuf); + if (result != ISC_R_SUCCESS) + goto failure; + + result = dns_tsigkey_create(&keyname, hmacname, secretstore, + secretsize, ISC_FALSE, NULL, 0, 0, mctx, + NULL, &key); + failure: + if (result != ISC_R_SUCCESS) + printf(";; Couldn't create key %s: %s\n", + keynametext, isc_result_totext(result)); + else + dst_key_setbits(key->key, digestbits); + + isc_mem_free(mctx, secretstore); + dns_name_invalidate(&keyname); + isc_buffer_free(&namebuf); +} + +static void +setup_file_key(void) { + isc_result_t result; + dst_key_t *dstkey = NULL; + + debug("setup_file_key()"); + result = dst_key_fromnamedfile(keyfile, DST_TYPE_PRIVATE | DST_TYPE_KEY, + mctx, &dstkey); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "Couldn't read key from %s: %s\n", + keyfile, isc_result_totext(result)); + goto failure; + } + + switch (dst_key_alg(dstkey)) { + case DST_ALG_HMACMD5: + hmacname = DNS_TSIG_HMACMD5_NAME; + break; + case DST_ALG_HMACSHA1: + hmacname = DNS_TSIG_HMACSHA1_NAME; + break; + case DST_ALG_HMACSHA224: + hmacname = DNS_TSIG_HMACSHA224_NAME; + break; + case DST_ALG_HMACSHA256: + hmacname = DNS_TSIG_HMACSHA256_NAME; + break; + case DST_ALG_HMACSHA384: + hmacname = DNS_TSIG_HMACSHA384_NAME; + break; + case DST_ALG_HMACSHA512: + hmacname = DNS_TSIG_HMACSHA512_NAME; + break; + default: + printf(";; Couldn't create key %s: bad algorithm\n", + keynametext); + goto failure; + } + result = dns_tsigkey_createfromkey(dst_key_name(dstkey), hmacname, + dstkey, ISC_FALSE, NULL, 0, 0, + mctx, NULL, &key); + if (result != ISC_R_SUCCESS) { + printf(";; Couldn't create key %s: %s\n", + keynametext, isc_result_totext(result)); + goto failure; + } + dstkey = NULL; + failure: + if (dstkey != NULL) + dst_key_free(&dstkey); +} + +static dig_searchlist_t * +make_searchlist_entry(char *domain) { + dig_searchlist_t *search; + search = isc_mem_allocate(mctx, sizeof(*search)); + if (search == NULL) + fatal("memory allocation failure in %s:%d", + __FILE__, __LINE__); + strncpy(search->origin, domain, MXNAME); + search->origin[MXNAME-1] = 0; + ISC_LINK_INIT(search, link); + return (search); +} + +static void +create_search_list(lwres_conf_t *confdata) { + int i; + dig_searchlist_t *search; + + debug("create_search_list()"); + ISC_LIST_INIT(search_list); + + for (i = 0; i < confdata->searchnxt; i++) { + search = make_searchlist_entry(confdata->search[i]); + ISC_LIST_APPEND(search_list, search, link); + } +} + +/*% + * Setup the system as a whole, reading key information and resolv.conf + * settings. + */ +void +setup_system(void) { + dig_searchlist_t *domain = NULL; + lwres_result_t lwresult; + unsigned int lwresflags; + + debug("setup_system()"); + + lwresflags = LWRES_CONTEXT_SERVERMODE; + if (have_ipv4) + lwresflags |= LWRES_CONTEXT_USEIPV4; + if (have_ipv6) + lwresflags |= LWRES_CONTEXT_USEIPV6; + + lwresult = lwres_context_create(&lwctx, mctx, mem_alloc, mem_free, + lwresflags); + if (lwresult != LWRES_R_SUCCESS) + fatal("lwres_context_create failed"); + + lwresult = lwres_conf_parse(lwctx, RESOLV_CONF); + if (lwresult != LWRES_R_SUCCESS && lwresult != LWRES_R_NOTFOUND) + fatal("parse of %s failed", RESOLV_CONF); + + lwconf = lwres_conf_get(lwctx); + + /* Make the search list */ + if (lwconf->searchnxt > 0) + create_search_list(lwconf); + else { /* No search list. Use the domain name if any */ + if (lwconf->domainname != NULL) { + domain = make_searchlist_entry(lwconf->domainname); + ISC_LIST_INITANDAPPEND(search_list, domain, link); + domain = NULL; + } + } + + if (ndots == -1) { + ndots = lwconf->ndots; + debug("ndots is %d.", ndots); + } + + /* If user doesn't specify server use nameservers from resolv.conf. */ + if (ISC_LIST_EMPTY(server_list)) + copy_server_list(lwconf, &server_list); + + /* If we don't find a nameserver fall back to localhost */ + if (ISC_LIST_EMPTY(server_list)) { + if (have_ipv4) { + lwresult = add_nameserver(lwconf, "127.0.0.1", AF_INET); + if (lwresult != ISC_R_SUCCESS) + fatal("add_nameserver failed"); + } + if (have_ipv6) { + lwresult = add_nameserver(lwconf, "::1", AF_INET6); + if (lwresult != ISC_R_SUCCESS) + fatal("add_nameserver failed"); + } + + copy_server_list(lwconf, &server_list); + } + +#ifdef WITH_IDN + initialize_idn(); +#endif + + if (keyfile[0] != 0) + setup_file_key(); + else if (keysecret[0] != 0) + setup_text_key(); +#ifdef DIG_SIGCHASE + /* Setup the list of messages for +sigchase */ + ISC_LIST_INIT(chase_message_list); + ISC_LIST_INIT(chase_message_list2); + dns_name_init(&chase_name, NULL); +#if DIG_SIGCHASE_TD + dns_name_init(&chase_current_name, NULL); + dns_name_init(&chase_authority_name, NULL); +#endif +#if DIG_SIGCHASE_BU + dns_name_init(&chase_signame, NULL); +#endif + +#endif + +} + +static void +clear_searchlist(void) { + dig_searchlist_t *search; + while ((search = ISC_LIST_HEAD(search_list)) != NULL) { + ISC_LIST_UNLINK(search_list, search, link); + isc_mem_free(mctx, search); + } +} + +/*% + * Override the search list derived from resolv.conf by 'domain'. + */ +void +set_search_domain(char *domain) { + dig_searchlist_t *search; + + clear_searchlist(); + search = make_searchlist_entry(domain); + ISC_LIST_APPEND(search_list, search, link); +} + +/*% + * Setup the ISC and DNS libraries for use by the system. + */ +void +setup_libs(void) { + isc_result_t result; + + debug("setup_libs()"); + + result = isc_net_probeipv4(); + if (result == ISC_R_SUCCESS) + have_ipv4 = ISC_TRUE; + + result = isc_net_probeipv6(); + if (result == ISC_R_SUCCESS) + have_ipv6 = ISC_TRUE; + if (!have_ipv6 && !have_ipv4) + fatal("can't find either v4 or v6 networking"); + + result = isc_mem_create(0, 0, &mctx); + check_result(result, "isc_mem_create"); + + result = isc_taskmgr_create(mctx, 1, 0, &taskmgr); + check_result(result, "isc_taskmgr_create"); + + result = isc_task_create(taskmgr, 0, &global_task); + check_result(result, "isc_task_create"); + + result = isc_timermgr_create(mctx, &timermgr); + check_result(result, "isc_timermgr_create"); + + result = isc_socketmgr_create(mctx, &socketmgr); + check_result(result, "isc_socketmgr_create"); + + result = isc_entropy_create(mctx, &entp); + check_result(result, "isc_entropy_create"); + + result = dst_lib_init(mctx, entp, 0); + check_result(result, "dst_lib_init"); + is_dst_up = ISC_TRUE; + + result = isc_mempool_create(mctx, COMMSIZE, &commctx); + check_result(result, "isc_mempool_create"); + isc_mempool_setname(commctx, "COMMPOOL"); + /* + * 6 and 2 set as reasonable parameters for 3 or 4 nameserver + * systems. + */ + isc_mempool_setfreemax(commctx, 6); + isc_mempool_setfillcount(commctx, 2); + + result = isc_mutex_init(&lookup_lock); + check_result(result, "isc_mutex_init"); + + dns_result_register(); +} + +/*% + * Add EDNS0 option record to a message. Currently, the only supported + * options are UDP buffer size, the DO bit, and NSID request. + */ +static void +add_opt(dns_message_t *msg, isc_uint16_t udpsize, isc_uint16_t edns, + isc_boolean_t dnssec, isc_boolean_t nsid) +{ + dns_rdataset_t *rdataset = NULL; + dns_rdatalist_t *rdatalist = NULL; + dns_rdata_t *rdata = NULL; + isc_result_t result; + + debug("add_opt()"); + result = dns_message_gettemprdataset(msg, &rdataset); + check_result(result, "dns_message_gettemprdataset"); + dns_rdataset_init(rdataset); + result = dns_message_gettemprdatalist(msg, &rdatalist); + check_result(result, "dns_message_gettemprdatalist"); + result = dns_message_gettemprdata(msg, &rdata); + check_result(result, "dns_message_gettemprdata"); + + debug("setting udp size of %d", udpsize); + rdatalist->type = dns_rdatatype_opt; + rdatalist->covers = 0; + rdatalist->rdclass = udpsize; + rdatalist->ttl = edns << 16; + if (dnssec) + rdatalist->ttl |= DNS_MESSAGEEXTFLAG_DO; + if (nsid) { + unsigned char data[4]; + isc_buffer_t buf; + + 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; + } + ISC_LIST_INIT(rdatalist->rdata); + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + dns_rdatalist_tordataset(rdatalist, rdataset); + result = dns_message_setopt(msg, rdataset); + check_result(result, "dns_message_setopt"); +} + +/*% + * Add a question section to a message, asking for the specified name, + * type, and class. + */ +static void +add_question(dns_message_t *message, dns_name_t *name, + dns_rdataclass_t rdclass, dns_rdatatype_t rdtype) +{ + dns_rdataset_t *rdataset; + isc_result_t result; + + debug("add_question()"); + rdataset = NULL; + result = dns_message_gettemprdataset(message, &rdataset); + check_result(result, "dns_message_gettemprdataset()"); + dns_rdataset_init(rdataset); + dns_rdataset_makequestion(rdataset, rdclass, rdtype); + ISC_LIST_APPEND(name->list, rdataset, link); +} + +/*% + * Check if we're done with all the queued lookups, which is true iff + * all sockets, sends, and recvs are accounted for (counters == 0), + * and the lookup list is empty. + * If we are done, pass control back out to dighost_shutdown() (which is + * part of dig.c, host.c, or nslookup.c) to either shutdown the system as + * a whole or reseed the lookup list. + */ +static void +check_if_done(void) { + debug("check_if_done()"); + debug("list %s", ISC_LIST_EMPTY(lookup_list) ? "empty" : "full"); + if (ISC_LIST_EMPTY(lookup_list) && current_lookup == NULL && + sendcount == 0) { + INSIST(sockcount == 0); + INSIST(recvcount == 0); + debug("shutting down"); + dighost_shutdown(); + } +} + +/*% + * Clear out a query when we're done with it. WARNING: This routine + * WILL invalidate the query pointer. + */ +static void +clear_query(dig_query_t *query) { + dig_lookup_t *lookup; + + REQUIRE(query != NULL); + + debug("clear_query(%p)", query); + + lookup = query->lookup; + + if (lookup->current_query == query) + lookup->current_query = NULL; + + ISC_LIST_UNLINK(lookup->q, query, link); + if (ISC_LINK_LINKED(&query->recvbuf, link)) + ISC_LIST_DEQUEUE(query->recvlist, &query->recvbuf, + link); + if (ISC_LINK_LINKED(&query->lengthbuf, link)) + ISC_LIST_DEQUEUE(query->lengthlist, &query->lengthbuf, + link); + INSIST(query->recvspace != NULL); + if (query->sock != NULL) { + isc_socket_detach(&query->sock); + sockcount--; + debug("sockcount=%d", sockcount); + } + isc_mempool_put(commctx, query->recvspace); + isc_buffer_invalidate(&query->recvbuf); + isc_buffer_invalidate(&query->lengthbuf); + if (query->waiting_senddone) + query->pending_free = ISC_TRUE; + else + isc_mem_free(mctx, query); +} + +/*% + * Try and clear out a lookup if we're done with it. Return ISC_TRUE if + * the lookup was successfully cleared. If ISC_TRUE is returned, the + * lookup pointer has been invalidated. + */ +static isc_boolean_t +try_clear_lookup(dig_lookup_t *lookup) { + dig_query_t *q; + + REQUIRE(lookup != NULL); + + debug("try_clear_lookup(%p)", lookup); + + if (ISC_LIST_HEAD(lookup->q) != NULL) { + if (debugging) { + q = ISC_LIST_HEAD(lookup->q); + while (q != NULL) { + debug("query to %s still pending", q->servname); + q = ISC_LIST_NEXT(q, link); + } + } + return (ISC_FALSE); + } + + /* + * At this point, we know there are no queries on the lookup, + * so can make it go away also. + */ + destroy_lookup(lookup); + return (ISC_TRUE); +} + +void +destroy_lookup(dig_lookup_t *lookup) { + dig_server_t *s; + void *ptr; + + debug("destroy"); + s = ISC_LIST_HEAD(lookup->my_server_list); + while (s != NULL) { + debug("freeing server %p belonging to %p", s, lookup); + ptr = s; + s = ISC_LIST_NEXT(s, link); + ISC_LIST_DEQUEUE(lookup->my_server_list, + (dig_server_t *)ptr, link); + isc_mem_free(mctx, ptr); + } + if (lookup->sendmsg != NULL) + dns_message_destroy(&lookup->sendmsg); + if (lookup->querysig != NULL) { + debug("freeing buffer %p", lookup->querysig); + isc_buffer_free(&lookup->querysig); + } + if (lookup->timer != NULL) + isc_timer_detach(&lookup->timer); + if (lookup->sendspace != NULL) + isc_mempool_put(commctx, lookup->sendspace); + + if (lookup->tsigctx != NULL) + dst_context_destroy(&lookup->tsigctx); + + isc_mem_free(mctx, lookup); +} + +/*% + * If we can, start the next lookup in the queue running. + * This assumes that the lookup on the head of the queue hasn't been + * started yet. It also removes the lookup from the head of the queue, + * setting the current_lookup pointer pointing to it. + */ +void +start_lookup(void) { + debug("start_lookup()"); + if (cancel_now) + return; + + /* + * If there's a current lookup running, we really shouldn't get + * here. + */ + INSIST(current_lookup == NULL); + + current_lookup = ISC_LIST_HEAD(lookup_list); + /* + * Put the current lookup somewhere so cancel_all can find it + */ + if (current_lookup != NULL) { + ISC_LIST_DEQUEUE(lookup_list, current_lookup, link); +#if DIG_SIGCHASE_TD + if (current_lookup->do_topdown && + !current_lookup->rdtype_sigchaseset) { + dst_key_t *trustedkey = NULL; + isc_buffer_t *b = NULL; + isc_region_t r; + isc_result_t result; + dns_name_t query_name; + dns_name_t *key_name; + int i; + + result = get_trusted_key(mctx); + if (result != ISC_R_SUCCESS) { + printf("\n;; No trusted key, " + "+sigchase option is disabled\n"); + current_lookup->sigchase = ISC_FALSE; + goto novalidation; + } + dns_name_init(&query_name, NULL); + nameFromString(current_lookup->textname, &query_name); + + for (i = 0; i < tk_list.nb_tk; i++) { + key_name = dst_key_name(tk_list.key[i]); + + if (dns_name_issubdomain(&query_name, + key_name) == ISC_TRUE) + trustedkey = tk_list.key[i]; + /* + * Verify temp is really the lowest + * WARNING + */ + } + if (trustedkey == NULL) { + printf("\n;; The queried zone: "); + dns_name_print(&query_name, stdout); + printf(" isn't a subdomain of any Trusted Keys" + ": +sigchase option is disable\n"); + current_lookup->sigchase = ISC_FALSE; + free_name(&query_name, mctx); + goto novalidation; + } + free_name(&query_name, mctx); + + current_lookup->rdtype_sigchase + = current_lookup->rdtype; + current_lookup->rdtype_sigchaseset + = current_lookup->rdtypeset; + current_lookup->rdtype = dns_rdatatype_ns; + + current_lookup->qrdtype_sigchase + = current_lookup->qrdtype; + current_lookup->qrdtype = dns_rdatatype_ns; + + current_lookup->rdclass_sigchase + = current_lookup->rdclass; + current_lookup->rdclass_sigchaseset + = current_lookup->rdclassset; + current_lookup->rdclass = dns_rdataclass_in; + + strncpy(current_lookup->textnamesigchase, + current_lookup->textname, MXNAME); + + current_lookup->trace_root_sigchase = ISC_TRUE; + + result = isc_buffer_allocate(mctx, &b, BUFSIZE); + check_result(result, "isc_buffer_allocate"); + result = dns_name_totext(dst_key_name(trustedkey), + ISC_FALSE, b); + check_result(result, "dns_name_totext"); + isc_buffer_usedregion(b, &r); + r.base[r.length] = '\0'; + strncpy(current_lookup->textname, (char*)r.base, + MXNAME); + isc_buffer_free(&b); + + nameFromString(current_lookup->textnamesigchase, + &chase_name); + + dns_name_init(&chase_authority_name, NULL); + } + novalidation: +#endif + setup_lookup(current_lookup); + do_lookup(current_lookup); + } else { + check_if_done(); + } +} + +/*% + * If we can, clear the current lookup and start the next one running. + * This calls try_clear_lookup, so may invalidate the lookup pointer. + */ +static void +check_next_lookup(dig_lookup_t *lookup) { + + INSIST(!free_now); + + debug("check_next_lookup(%p)", lookup); + + if (ISC_LIST_HEAD(lookup->q) != NULL) { + debug("still have a worker"); + return; + } + if (try_clear_lookup(lookup)) { + current_lookup = NULL; + start_lookup(); + } +} + +/*% + * Create and queue a new lookup as a followup to the current lookup, + * based on the supplied message and section. This is used in trace and + * name server search modes to start a new lookup using servers from + * NS records in a reply. Returns the number of followup lookups made. + */ +static int +followup_lookup(dns_message_t *msg, dig_query_t *query, dns_section_t section) +{ + dig_lookup_t *lookup = NULL; + dig_server_t *srv = NULL; + dns_rdataset_t *rdataset = NULL; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_name_t *name = NULL; + isc_result_t result; + isc_boolean_t success = ISC_FALSE; + int numLookups = 0; + dns_name_t *domain; + isc_boolean_t horizontal = ISC_FALSE, bad = ISC_FALSE; + + INSIST(!free_now); + + debug("following up %s", query->lookup->textname); + + for (result = dns_message_firstname(msg, section); + result == ISC_R_SUCCESS; + result = dns_message_nextname(msg, section)) { + name = NULL; + dns_message_currentname(msg, section, &name); + + if (section == DNS_SECTION_AUTHORITY) { + rdataset = NULL; + result = dns_message_findtype(name, dns_rdatatype_soa, + 0, &rdataset); + if (result == ISC_R_SUCCESS) + return (0); + } + rdataset = NULL; + result = dns_message_findtype(name, dns_rdatatype_ns, 0, + &rdataset); + if (result != ISC_R_SUCCESS) + continue; + + debug("found NS set"); + + if (query->lookup->trace && !query->lookup->trace_root) { + dns_namereln_t namereln; + unsigned int nlabels; + int order; + + domain = dns_fixedname_name(&query->lookup->fdomain); + namereln = dns_name_fullcompare(name, domain, + &order, &nlabels); + if (namereln == dns_namereln_equal) { + if (!horizontal) + printf(";; BAD (HORIZONTAL) REFERRAL\n"); + horizontal = ISC_TRUE; + } else if (namereln != dns_namereln_subdomain) { + if (!bad) + printf(";; BAD REFERRAL\n"); + bad = ISC_TRUE; + continue; + } + } + + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) { + char namestr[DNS_NAME_FORMATSIZE]; + dns_rdata_ns_t ns; + + if (query->lookup->trace_root && + query->lookup->nsfound >= MXSERV) + break; + + dns_rdataset_current(rdataset, &rdata); + + query->lookup->nsfound++; + result = dns_rdata_tostruct(&rdata, &ns, NULL); + check_result(result, "dns_rdata_tostruct"); + dns_name_format(&ns.name, namestr, sizeof(namestr)); + dns_rdata_freestruct(&ns); + + /* Initialize lookup if we've not yet */ + debug("found NS %d %s", numLookups, namestr); + numLookups++; + if (!success) { + success = ISC_TRUE; + lookup_counter++; + lookup = requeue_lookup(query->lookup, + ISC_FALSE); + cancel_lookup(query->lookup); + lookup->doing_xfr = ISC_FALSE; + if (!lookup->trace_root && + section == DNS_SECTION_ANSWER) + lookup->trace = ISC_FALSE; + else + lookup->trace = query->lookup->trace; + lookup->ns_search_only = + query->lookup->ns_search_only; + lookup->trace_root = ISC_FALSE; + if (lookup->ns_search_only) + lookup->recurse = ISC_FALSE; + dns_fixedname_init(&lookup->fdomain); + domain = dns_fixedname_name(&lookup->fdomain); + dns_name_copy(name, domain, NULL); + } + srv = make_server(namestr, namestr); + debug("adding server %s", srv->servername); + ISC_LIST_APPEND(lookup->my_server_list, srv, link); + dns_rdata_reset(&rdata); + } + } + + if (lookup == NULL && + section == DNS_SECTION_ANSWER && + (query->lookup->trace || query->lookup->ns_search_only)) + return (followup_lookup(msg, query, DNS_SECTION_AUTHORITY)); + + /* + * Randomize the order the nameserver will be tried. + */ + if (numLookups > 1) { + isc_uint32_t i, j; + dig_serverlist_t my_server_list; + + ISC_LIST_INIT(my_server_list); + + for (i = numLookups; i > 0; i--) { + isc_random_get(&j); + j %= i; + srv = ISC_LIST_HEAD(lookup->my_server_list); + while (j-- > 0) + srv = ISC_LIST_NEXT(srv, link); + ISC_LIST_DEQUEUE(lookup->my_server_list, srv, link); + ISC_LIST_APPEND(my_server_list, srv, link); + } + ISC_LIST_APPENDLIST(lookup->my_server_list, + my_server_list, link); + } + + return (numLookups); +} + +/*% + * Create and queue a new lookup using the next origin from the search + * list, read in setup_system(). + * + * Return ISC_TRUE iff there was another searchlist entry. + */ +static isc_boolean_t +next_origin(dns_message_t *msg, dig_query_t *query) { + dig_lookup_t *lookup; + dig_searchlist_t *search; + + UNUSED(msg); + + INSIST(!free_now); + + debug("next_origin()"); + debug("following up %s", query->lookup->textname); + + if (!usesearch) + /* + * We're not using a search list, so don't even think + * about finding the next entry. + */ + return (ISC_FALSE); + if (query->lookup->origin == NULL && !query->lookup->need_search) + /* + * Then we just did rootorg; there's nothing left. + */ + return (ISC_FALSE); + if (query->lookup->origin == NULL && query->lookup->need_search) { + lookup = requeue_lookup(query->lookup, ISC_TRUE); + lookup->origin = ISC_LIST_HEAD(search_list); + lookup->need_search = ISC_FALSE; + } else { + search = ISC_LIST_NEXT(query->lookup->origin, link); + if (search == NULL && query->lookup->done_as_is) + return (ISC_FALSE); + lookup = requeue_lookup(query->lookup, ISC_TRUE); + lookup->origin = search; + } + cancel_lookup(query->lookup); + return (ISC_TRUE); +} + +/*% + * Insert an SOA record into the sendmessage in a lookup. Used for + * creating IXFR queries. + */ +static void +insert_soa(dig_lookup_t *lookup) { + isc_result_t result; + dns_rdata_soa_t soa; + dns_rdata_t *rdata = NULL; + dns_rdatalist_t *rdatalist = NULL; + dns_rdataset_t *rdataset = NULL; + dns_name_t *soaname = NULL; + + debug("insert_soa()"); + soa.mctx = mctx; + soa.serial = lookup->ixfr_serial; + soa.refresh = 0; + soa.retry = 0; + soa.expire = 0; + soa.minimum = 0; + soa.common.rdclass = lookup->rdclass; + soa.common.rdtype = dns_rdatatype_soa; + + dns_name_init(&soa.origin, NULL); + dns_name_init(&soa.contact, NULL); + + dns_name_clone(dns_rootname, &soa.origin); + dns_name_clone(dns_rootname, &soa.contact); + + isc_buffer_init(&lookup->rdatabuf, lookup->rdatastore, + sizeof(lookup->rdatastore)); + + result = dns_message_gettemprdata(lookup->sendmsg, &rdata); + check_result(result, "dns_message_gettemprdata"); + + result = dns_rdata_fromstruct(rdata, lookup->rdclass, + dns_rdatatype_soa, &soa, + &lookup->rdatabuf); + check_result(result, "isc_rdata_fromstruct"); + + result = dns_message_gettemprdatalist(lookup->sendmsg, &rdatalist); + check_result(result, "dns_message_gettemprdatalist"); + + result = dns_message_gettemprdataset(lookup->sendmsg, &rdataset); + check_result(result, "dns_message_gettemprdataset"); + + dns_rdatalist_init(rdatalist); + rdatalist->type = dns_rdatatype_soa; + rdatalist->rdclass = lookup->rdclass; + rdatalist->covers = 0; + rdatalist->ttl = 0; + ISC_LIST_INIT(rdatalist->rdata); + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + + dns_rdataset_init(rdataset); + dns_rdatalist_tordataset(rdatalist, rdataset); + + result = dns_message_gettempname(lookup->sendmsg, &soaname); + check_result(result, "dns_message_gettempname"); + dns_name_init(soaname, NULL); + dns_name_clone(lookup->name, soaname); + ISC_LIST_INIT(soaname->list); + ISC_LIST_APPEND(soaname->list, rdataset, link); + dns_message_addname(lookup->sendmsg, soaname, DNS_SECTION_AUTHORITY); +} + +/*% + * Setup the supplied lookup structure, making it ready to start sending + * queries to servers. Create and initialize the message to be sent as + * well as the query structures and buffer space for the replies. If the + * server list is empty, clone it from the system default list. + */ +void +setup_lookup(dig_lookup_t *lookup) { + isc_result_t result; + isc_uint32_t id; + int len; + dig_server_t *serv; + dig_query_t *query; + isc_buffer_t b; + dns_compress_t cctx; + char store[MXNAME]; +#ifdef WITH_IDN + idn_result_t mr; + char utf8_textname[MXNAME], utf8_origin[MXNAME], idn_textname[MXNAME]; +#endif + +#ifdef WITH_IDN + result = dns_name_settotextfilter(output_filter); + check_result(result, "dns_name_settotextfilter"); +#endif + + REQUIRE(lookup != NULL); + INSIST(!free_now); + + debug("setup_lookup(%p)", lookup); + + result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, + &lookup->sendmsg); + check_result(result, "dns_message_create"); + + if (lookup->new_search) { + debug("resetting lookup counter."); + lookup_counter = 0; + } + + if (ISC_LIST_EMPTY(lookup->my_server_list)) { + debug("cloning server list"); + clone_server_list(server_list, &lookup->my_server_list); + } + result = dns_message_gettempname(lookup->sendmsg, &lookup->name); + check_result(result, "dns_message_gettempname"); + dns_name_init(lookup->name, NULL); + + isc_buffer_init(&lookup->namebuf, lookup->namespace, + sizeof(lookup->namespace)); + isc_buffer_init(&lookup->onamebuf, lookup->onamespace, + sizeof(lookup->onamespace)); + +#ifdef WITH_IDN + /* + * We cannot convert `textname' and `origin' separately. + * `textname' doesn't contain TLD, but local mapping needs + * TLD. + */ + mr = idn_encodename(IDN_LOCALCONV | IDN_DELIMMAP, lookup->textname, + utf8_textname, sizeof(utf8_textname)); + idn_check_result(mr, "convert textname to UTF-8"); +#endif + + /* + * If the name has too many dots, force the origin to be NULL + * (which produces an absolute lookup). Otherwise, take the origin + * we have if there's one in the struct already. If it's NULL, + * take the first entry in the searchlist iff either usesearch + * is TRUE or we got a domain line in the resolv.conf file. + */ + if (lookup->new_search) { +#ifdef WITH_IDN + if ((count_dots(utf8_textname) >= ndots) || !usesearch) { + lookup->origin = NULL; /* Force abs lookup */ + lookup->done_as_is = ISC_TRUE; + lookup->need_search = usesearch; + } else if (lookup->origin == NULL && usesearch) { + lookup->origin = ISC_LIST_HEAD(search_list); + lookup->need_search = ISC_FALSE; + } +#else + if ((count_dots(lookup->textname) >= ndots) || !usesearch) { + lookup->origin = NULL; /* Force abs lookup */ + lookup->done_as_is = ISC_TRUE; + lookup->need_search = usesearch; + } else if (lookup->origin == NULL && usesearch) { + lookup->origin = ISC_LIST_HEAD(search_list); + lookup->need_search = ISC_FALSE; + } +#endif + } + +#ifdef WITH_IDN + if (lookup->origin != NULL) { + mr = idn_encodename(IDN_LOCALCONV | IDN_DELIMMAP, + lookup->origin->origin, utf8_origin, + sizeof(utf8_origin)); + idn_check_result(mr, "convert origin to UTF-8"); + mr = append_textname(utf8_textname, utf8_origin, + sizeof(utf8_textname)); + idn_check_result(mr, "append origin to textname"); + } + mr = idn_encodename(idnoptions | IDN_LOCALMAP | IDN_NAMEPREP | + IDN_IDNCONV | IDN_LENCHECK, utf8_textname, + idn_textname, sizeof(idn_textname)); + idn_check_result(mr, "convert UTF-8 textname to IDN encoding"); +#else + if (lookup->origin != NULL) { + debug("trying origin %s", lookup->origin->origin); + result = dns_message_gettempname(lookup->sendmsg, + &lookup->oname); + check_result(result, "dns_message_gettempname"); + dns_name_init(lookup->oname, NULL); + /* XXX Helper funct to conv char* to name? */ + len = strlen(lookup->origin->origin); + isc_buffer_init(&b, lookup->origin->origin, len); + isc_buffer_add(&b, len); + result = dns_name_fromtext(lookup->oname, &b, dns_rootname, + ISC_FALSE, &lookup->onamebuf); + if (result != ISC_R_SUCCESS) { + dns_message_puttempname(lookup->sendmsg, + &lookup->name); + dns_message_puttempname(lookup->sendmsg, + &lookup->oname); + fatal("'%s' is not in legal name syntax (%s)", + lookup->origin->origin, + isc_result_totext(result)); + } + if (lookup->trace && lookup->trace_root) { + dns_name_clone(dns_rootname, lookup->name); + } else { + len = strlen(lookup->textname); + isc_buffer_init(&b, lookup->textname, len); + isc_buffer_add(&b, len); + result = dns_name_fromtext(lookup->name, &b, + lookup->oname, ISC_FALSE, + &lookup->namebuf); + } + if (result != ISC_R_SUCCESS) { + dns_message_puttempname(lookup->sendmsg, + &lookup->name); + dns_message_puttempname(lookup->sendmsg, + &lookup->oname); + fatal("'%s' is not in legal name syntax (%s)", + lookup->textname, isc_result_totext(result)); + } + dns_message_puttempname(lookup->sendmsg, &lookup->oname); + } else +#endif + { + debug("using root origin"); + if (lookup->trace && lookup->trace_root) + dns_name_clone(dns_rootname, lookup->name); + else { +#ifdef WITH_IDN + len = strlen(idn_textname); + isc_buffer_init(&b, idn_textname, len); + isc_buffer_add(&b, len); + result = dns_name_fromtext(lookup->name, &b, + dns_rootname, + ISC_FALSE, + &lookup->namebuf); +#else + len = strlen(lookup->textname); + isc_buffer_init(&b, lookup->textname, len); + isc_buffer_add(&b, len); + result = dns_name_fromtext(lookup->name, &b, + dns_rootname, + ISC_FALSE, + &lookup->namebuf); +#endif + } + if (result != ISC_R_SUCCESS) { + dns_message_puttempname(lookup->sendmsg, + &lookup->name); + isc_buffer_init(&b, store, MXNAME); + fatal("'%s' is not a legal name " + "(%s)", lookup->textname, + isc_result_totext(result)); + } + } + dns_name_format(lookup->name, store, sizeof(store)); + trying(store, lookup); + INSIST(dns_name_isabsolute(lookup->name)); + + isc_random_get(&id); + lookup->sendmsg->id = (unsigned short)id & 0xFFFF; + lookup->sendmsg->opcode = dns_opcode_query; + lookup->msgcounter = 0; + /* + * If this is a trace request, completely disallow recursion, since + * it's meaningless for traces. + */ + if (lookup->trace || (lookup->ns_search_only && !lookup->trace_root)) + lookup->recurse = ISC_FALSE; + + if (lookup->recurse && + lookup->rdtype != dns_rdatatype_axfr && + lookup->rdtype != dns_rdatatype_ixfr) { + debug("recursive query"); + lookup->sendmsg->flags |= DNS_MESSAGEFLAG_RD; + } + + /* XXX aaflag */ + if (lookup->aaonly) { + debug("AA query"); + lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AA; + } + + if (lookup->adflag) { + debug("AD query"); + lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AD; + } + + if (lookup->cdflag) { + debug("CD query"); + lookup->sendmsg->flags |= DNS_MESSAGEFLAG_CD; + } + + dns_message_addname(lookup->sendmsg, lookup->name, + DNS_SECTION_QUESTION); + + if (lookup->trace && lookup->trace_root) { + lookup->qrdtype = lookup->rdtype; + lookup->rdtype = dns_rdatatype_ns; + } + + if ((lookup->rdtype == dns_rdatatype_axfr) || + (lookup->rdtype == dns_rdatatype_ixfr)) { + /* + * Force TCP mode if we're doing an axfr. + */ + if (lookup->rdtype == dns_rdatatype_axfr) { + lookup->doing_xfr = ISC_TRUE; + lookup->tcp_mode = ISC_TRUE; + } else if (lookup->tcp_mode) { + lookup->doing_xfr = ISC_TRUE; + } + } + + add_question(lookup->sendmsg, lookup->name, lookup->rdclass, + lookup->rdtype); + + /* add_soa */ + if (lookup->rdtype == dns_rdatatype_ixfr) + insert_soa(lookup); + + /* XXX Insist this? */ + lookup->tsigctx = NULL; + lookup->querysig = NULL; + if (key != NULL) { + debug("initializing keys"); + result = dns_message_settsigkey(lookup->sendmsg, key); + check_result(result, "dns_message_settsigkey"); + } + + lookup->sendspace = isc_mempool_get(commctx); + if (lookup->sendspace == NULL) + fatal("memory allocation failure"); + + result = dns_compress_init(&cctx, -1, mctx); + check_result(result, "dns_compress_init"); + + debug("starting to render the message"); + isc_buffer_init(&lookup->renderbuf, lookup->sendspace, COMMSIZE); + result = dns_message_renderbegin(lookup->sendmsg, &cctx, + &lookup->renderbuf); + check_result(result, "dns_message_renderbegin"); + if (lookup->udpsize > 0 || lookup->dnssec || lookup->edns > -1) { + if (lookup->udpsize == 0) + lookup->udpsize = 4096; + if (lookup->edns < 0) + lookup->edns = 0; + add_opt(lookup->sendmsg, lookup->udpsize, + lookup->edns, lookup->dnssec, lookup->nsid); + } + + result = dns_message_rendersection(lookup->sendmsg, + DNS_SECTION_QUESTION, 0); + check_result(result, "dns_message_rendersection"); + result = dns_message_rendersection(lookup->sendmsg, + DNS_SECTION_AUTHORITY, 0); + check_result(result, "dns_message_rendersection"); + result = dns_message_renderend(lookup->sendmsg); + check_result(result, "dns_message_renderend"); + debug("done rendering"); + + dns_compress_invalidate(&cctx); + + /* + * Force TCP mode if the request is larger than 512 bytes. + */ + if (isc_buffer_usedlength(&lookup->renderbuf) > 512) + lookup->tcp_mode = ISC_TRUE; + + lookup->pending = ISC_FALSE; + + for (serv = ISC_LIST_HEAD(lookup->my_server_list); + serv != NULL; + serv = ISC_LIST_NEXT(serv, link)) { + query = isc_mem_allocate(mctx, sizeof(dig_query_t)); + if (query == NULL) + fatal("memory allocation failure in %s:%d", + __FILE__, __LINE__); + debug("create query %p linked to lookup %p", + query, lookup); + query->lookup = lookup; + query->waiting_connect = ISC_FALSE; + query->waiting_senddone = ISC_FALSE; + query->pending_free = ISC_FALSE; + query->recv_made = ISC_FALSE; + query->first_pass = ISC_TRUE; + query->first_soa_rcvd = ISC_FALSE; + query->second_rr_rcvd = ISC_FALSE; + query->first_repeat_rcvd = ISC_FALSE; + query->warn_id = ISC_TRUE; + query->first_rr_serial = 0; + query->second_rr_serial = 0; + query->servname = serv->servername; + query->userarg = serv->userarg; + query->rr_count = 0; + query->msg_count = 0; + query->byte_count = 0; + ISC_LINK_INIT(query, link); + ISC_LIST_INIT(query->recvlist); + ISC_LIST_INIT(query->lengthlist); + query->sock = NULL; + query->recvspace = isc_mempool_get(commctx); + if (query->recvspace == NULL) + fatal("memory allocation failure"); + + isc_buffer_init(&query->recvbuf, query->recvspace, COMMSIZE); + isc_buffer_init(&query->lengthbuf, query->lengthspace, 2); + isc_buffer_init(&query->slbuf, query->slspace, 2); + query->sendbuf = lookup->renderbuf; + + ISC_LINK_INIT(query, link); + ISC_LIST_ENQUEUE(lookup->q, query, link); + } + /* XXX qrflag, print_query, etc... */ + if (!ISC_LIST_EMPTY(lookup->q) && qr) { + extrabytes = 0; + printmessage(ISC_LIST_HEAD(lookup->q), lookup->sendmsg, + ISC_TRUE); + } +} + +/*% + * Event handler for send completion. Track send counter, and clear out + * the query if the send was canceled. + */ +static void +send_done(isc_task_t *_task, isc_event_t *event) { + isc_socketevent_t *sevent = (isc_socketevent_t *)event; + isc_buffer_t *b = NULL; + dig_query_t *query, *next; + dig_lookup_t *l; + + REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE); + + UNUSED(_task); + + LOCK_LOOKUP; + + debug("send_done()"); + sendcount--; + debug("sendcount=%d", sendcount); + INSIST(sendcount >= 0); + + for (b = ISC_LIST_HEAD(sevent->bufferlist); + b != NULL; + b = ISC_LIST_HEAD(sevent->bufferlist)) + ISC_LIST_DEQUEUE(sevent->bufferlist, b, link); + + query = event->ev_arg; + query->waiting_senddone = ISC_FALSE; + l = query->lookup; + + if (l->ns_search_only && !l->trace_root) { + debug("sending next, since searching"); + next = ISC_LIST_NEXT(query, link); + if (next != NULL) + send_udp(next); + } + + isc_event_free(&event); + + if (query->pending_free) + isc_mem_free(mctx, query); + + check_if_done(); + UNLOCK_LOOKUP; +} + +/*% + * Cancel a lookup, sending isc_socket_cancel() requests to all outstanding + * IO sockets. The cancel handlers should take care of cleaning up the + * query and lookup structures + */ +static void +cancel_lookup(dig_lookup_t *lookup) { + dig_query_t *query, *next; + + debug("cancel_lookup()"); + query = ISC_LIST_HEAD(lookup->q); + while (query != NULL) { + next = ISC_LIST_NEXT(query, link); + if (query->sock != NULL) { + isc_socket_cancel(query->sock, global_task, + ISC_SOCKCANCEL_ALL); + check_if_done(); + } else { + clear_query(query); + } + query = next; + } + if (lookup->timer != NULL) + isc_timer_detach(&lookup->timer); + lookup->pending = ISC_FALSE; + lookup->retries = 0; +} + +static void +bringup_timer(dig_query_t *query, unsigned int default_timeout) { + dig_lookup_t *l; + unsigned int local_timeout; + isc_result_t result; + + debug("bringup_timer()"); + /* + * If the timer already exists, that means we're calling this + * a second time (for a retry). Don't need to recreate it, + * just reset it. + */ + l = query->lookup; + if (ISC_LIST_NEXT(query, link) != NULL) + local_timeout = SERVER_TIMEOUT; + else { + if (timeout == 0) + local_timeout = default_timeout; + else + local_timeout = timeout; + } + debug("have local timeout of %d", local_timeout); + isc_interval_set(&l->interval, local_timeout, 0); + if (l->timer != NULL) + isc_timer_detach(&l->timer); + result = isc_timer_create(timermgr, isc_timertype_once, NULL, + &l->interval, global_task, connect_timeout, + l, &l->timer); + check_result(result, "isc_timer_create"); +} + +static void +force_timeout(dig_lookup_t *l, dig_query_t *query) { + isc_event_t *event; + + event = isc_event_allocate(mctx, query, ISC_TIMEREVENT_IDLE, + connect_timeout, l, + sizeof(isc_event_t)); + if (event == NULL) { + fatal("isc_event_allocate: %s", + isc_result_totext(ISC_R_NOMEMORY)); + } + isc_task_send(global_task, &event); +} + + +static void +connect_done(isc_task_t *task, isc_event_t *event); + +/*% + * Unlike send_udp, this can't be called multiple times with the same + * query. When we retry TCP, we requeue the whole lookup, which should + * start anew. + */ +static void +send_tcp_connect(dig_query_t *query) { + isc_result_t result; + dig_query_t *next; + dig_lookup_t *l; + + debug("send_tcp_connect(%p)", query); + + l = query->lookup; + query->waiting_connect = ISC_TRUE; + query->lookup->current_query = query; + result = get_address(query->servname, port, &query->sockaddr); + if (result == ISC_R_NOTFOUND) { + /* + * This servname doesn't have an address. Try the next server + * by triggering an immediate 'timeout' (we lie, but the effect + * is the same). + */ + force_timeout(l, query); + return; + } + + if (specified_source && + (isc_sockaddr_pf(&query->sockaddr) != + isc_sockaddr_pf(&bind_address))) { + printf(";; Skipping server %s, incompatible " + "address family\n", query->servname); + query->waiting_connect = ISC_FALSE; + next = ISC_LIST_NEXT(query, link); + l = query->lookup; + clear_query(query); + if (next == NULL) { + printf(";; No acceptable nameservers\n"); + check_next_lookup(l); + return; + } + send_tcp_connect(next); + return; + } + INSIST(query->sock == NULL); + result = isc_socket_create(socketmgr, + isc_sockaddr_pf(&query->sockaddr), + isc_sockettype_tcp, &query->sock); + check_result(result, "isc_socket_create"); + sockcount++; + debug("sockcount=%d", sockcount); + if (specified_source) + result = isc_socket_bind(query->sock, &bind_address, + ISC_SOCKET_REUSEADDRESS); + else { + if ((isc_sockaddr_pf(&query->sockaddr) == AF_INET) && + have_ipv4) + isc_sockaddr_any(&bind_any); + else + isc_sockaddr_any6(&bind_any); + result = isc_socket_bind(query->sock, &bind_any, 0); + } + check_result(result, "isc_socket_bind"); + bringup_timer(query, TCP_TIMEOUT); + result = isc_socket_connect(query->sock, &query->sockaddr, + global_task, connect_done, query); + check_result(result, "isc_socket_connect"); + /* + * If we're at the endgame of a nameserver search, we need to + * immediately bring up all the queries. Do it here. + */ + if (l->ns_search_only && !l->trace_root) { + debug("sending next, since searching"); + next = ISC_LIST_NEXT(query, link); + if (next != NULL) + send_tcp_connect(next); + } +} + +/*% + * Send a UDP packet to the remote nameserver, possible starting the + * recv action as well. Also make sure that the timer is running and + * is properly reset. + */ +static void +send_udp(dig_query_t *query) { + dig_lookup_t *l = NULL; + isc_result_t result; + + debug("send_udp(%p)", query); + + l = query->lookup; + bringup_timer(query, UDP_TIMEOUT); + l->current_query = query; + debug("working on lookup %p, query %p", query->lookup, query); + if (!query->recv_made) { + /* XXX Check the sense of this, need assertion? */ + query->waiting_connect = ISC_FALSE; + result = get_address(query->servname, port, &query->sockaddr); + if (result == ISC_R_NOTFOUND) { + /* This servname doesn't have an address. */ + force_timeout(l, query); + return; + } + + result = isc_socket_create(socketmgr, + isc_sockaddr_pf(&query->sockaddr), + isc_sockettype_udp, &query->sock); + check_result(result, "isc_socket_create"); + sockcount++; + debug("sockcount=%d", sockcount); + if (specified_source) { + result = isc_socket_bind(query->sock, &bind_address, + ISC_SOCKET_REUSEADDRESS); + } else { + isc_sockaddr_anyofpf(&bind_any, + isc_sockaddr_pf(&query->sockaddr)); + result = isc_socket_bind(query->sock, &bind_any, 0); + } + check_result(result, "isc_socket_bind"); + + query->recv_made = ISC_TRUE; + ISC_LINK_INIT(&query->recvbuf, link); + ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf, + link); + debug("recving with lookup=%p, query=%p, sock=%p", + query->lookup, query, query->sock); + result = isc_socket_recvv(query->sock, &query->recvlist, 1, + global_task, recv_done, query); + check_result(result, "isc_socket_recvv"); + recvcount++; + debug("recvcount=%d", recvcount); + } + ISC_LIST_INIT(query->sendlist); + ISC_LIST_ENQUEUE(query->sendlist, &query->sendbuf, link); + debug("sending a request"); + TIME_NOW(&query->time_sent); + INSIST(query->sock != NULL); + query->waiting_senddone = ISC_TRUE; + result = isc_socket_sendtov(query->sock, &query->sendlist, + global_task, send_done, query, + &query->sockaddr, NULL); + check_result(result, "isc_socket_sendtov"); + sendcount++; +} + +/*% + * IO timeout handler, used for both connect and recv timeouts. If + * retries are still allowed, either resend the UDP packet or queue a + * new TCP lookup. Otherwise, cancel the lookup. + */ +static void +connect_timeout(isc_task_t *task, isc_event_t *event) { + dig_lookup_t *l = NULL; + dig_query_t *query = NULL, *cq; + + UNUSED(task); + REQUIRE(event->ev_type == ISC_TIMEREVENT_IDLE); + + debug("connect_timeout()"); + + LOCK_LOOKUP; + l = event->ev_arg; + query = l->current_query; + isc_event_free(&event); + + INSIST(!free_now); + + if ((query != NULL) && (query->lookup->current_query != NULL) && + (ISC_LIST_NEXT(query->lookup->current_query, link) != NULL)) { + debug("trying next server..."); + cq = query->lookup->current_query; + if (!l->tcp_mode) + send_udp(ISC_LIST_NEXT(cq, link)); + else { + isc_socket_cancel(query->sock, NULL, + ISC_SOCKCANCEL_ALL); + isc_socket_detach(&query->sock); + sockcount--; + debug("sockcount=%d", sockcount); + send_tcp_connect(ISC_LIST_NEXT(cq, link)); + } + UNLOCK_LOOKUP; + return; + } + + if (l->retries > 1) { + if (!l->tcp_mode) { + l->retries--; + debug("resending UDP request to first server"); + send_udp(ISC_LIST_HEAD(l->q)); + } else { + debug("making new TCP request, %d tries left", + l->retries); + l->retries--; + requeue_lookup(l, ISC_TRUE); + cancel_lookup(l); + check_next_lookup(l); + } + } else { + fputs(l->cmdline, stdout); + printf(";; connection timed out; no servers could be " + "reached\n"); + cancel_lookup(l); + check_next_lookup(l); + if (exitcode < 9) + exitcode = 9; + } + UNLOCK_LOOKUP; +} + +/*% + * Event handler for the TCP recv which gets the length header of TCP + * packets. Start the next recv of length bytes. + */ +static void +tcp_length_done(isc_task_t *task, isc_event_t *event) { + isc_socketevent_t *sevent; + isc_buffer_t *b = NULL; + isc_result_t result; + dig_query_t *query = NULL; + dig_lookup_t *l; + isc_uint16_t length; + + REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE); + INSIST(!free_now); + + UNUSED(task); + + debug("tcp_length_done()"); + + LOCK_LOOKUP; + sevent = (isc_socketevent_t *)event; + query = event->ev_arg; + + recvcount--; + INSIST(recvcount >= 0); + + b = ISC_LIST_HEAD(sevent->bufferlist); + INSIST(b == &query->lengthbuf); + ISC_LIST_DEQUEUE(sevent->bufferlist, b, link); + + if (sevent->result == ISC_R_CANCELED) { + isc_event_free(&event); + l = query->lookup; + clear_query(query); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } + if (sevent->result != ISC_R_SUCCESS) { + char sockstr[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_format(&query->sockaddr, sockstr, + sizeof(sockstr)); + printf(";; communications error to %s: %s\n", + sockstr, isc_result_totext(sevent->result)); + l = query->lookup; + isc_socket_detach(&query->sock); + sockcount--; + debug("sockcount=%d", sockcount); + INSIST(sockcount >= 0); + isc_event_free(&event); + clear_query(query); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } + length = isc_buffer_getuint16(b); + if (length == 0) { + isc_event_free(&event); + launch_next_query(query, ISC_FALSE); + UNLOCK_LOOKUP; + return; + } + + /* + * Even though the buffer was already init'ed, we need + * to redo it now, to force the length we want. + */ + isc_buffer_invalidate(&query->recvbuf); + isc_buffer_init(&query->recvbuf, query->recvspace, length); + ENSURE(ISC_LIST_EMPTY(query->recvlist)); + ISC_LINK_INIT(&query->recvbuf, link); + ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf, link); + debug("recving with lookup=%p, query=%p", query->lookup, query); + result = isc_socket_recvv(query->sock, &query->recvlist, length, task, + recv_done, query); + check_result(result, "isc_socket_recvv"); + recvcount++; + debug("resubmitted recv request with length %d, recvcount=%d", + length, recvcount); + isc_event_free(&event); + UNLOCK_LOOKUP; +} + +/*% + * For transfers that involve multiple recvs (XFR's in particular), + * launch the next recv. + */ +static void +launch_next_query(dig_query_t *query, isc_boolean_t include_question) { + isc_result_t result; + dig_lookup_t *l; + + INSIST(!free_now); + + debug("launch_next_query()"); + + if (!query->lookup->pending) { + debug("ignoring launch_next_query because !pending"); + isc_socket_detach(&query->sock); + sockcount--; + debug("sockcount=%d", sockcount); + INSIST(sockcount >= 0); + query->waiting_connect = ISC_FALSE; + l = query->lookup; + clear_query(query); + check_next_lookup(l); + return; + } + + isc_buffer_clear(&query->slbuf); + isc_buffer_clear(&query->lengthbuf); + isc_buffer_putuint16(&query->slbuf, (isc_uint16_t) query->sendbuf.used); + ISC_LIST_INIT(query->sendlist); + ISC_LINK_INIT(&query->slbuf, link); + ISC_LIST_ENQUEUE(query->sendlist, &query->slbuf, link); + if (include_question) + ISC_LIST_ENQUEUE(query->sendlist, &query->sendbuf, link); + ISC_LINK_INIT(&query->lengthbuf, link); + ISC_LIST_ENQUEUE(query->lengthlist, &query->lengthbuf, link); + + result = isc_socket_recvv(query->sock, &query->lengthlist, 0, + global_task, tcp_length_done, query); + check_result(result, "isc_socket_recvv"); + recvcount++; + debug("recvcount=%d", recvcount); + if (!query->first_soa_rcvd) { + debug("sending a request in launch_next_query"); + TIME_NOW(&query->time_sent); + query->waiting_senddone = ISC_TRUE; + result = isc_socket_sendv(query->sock, &query->sendlist, + global_task, send_done, query); + check_result(result, "isc_socket_sendv"); + sendcount++; + debug("sendcount=%d", sendcount); + } + query->waiting_connect = ISC_FALSE; +#if 0 + check_next_lookup(query->lookup); +#endif + return; +} + +/*% + * Event handler for TCP connect complete. Make sure the connection was + * successful, then pass into launch_next_query to actually send the + * question. + */ +static void +connect_done(isc_task_t *task, isc_event_t *event) { + isc_socketevent_t *sevent = NULL; + dig_query_t *query = NULL, *next; + dig_lookup_t *l; + + UNUSED(task); + + REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT); + INSIST(!free_now); + + debug("connect_done()"); + + LOCK_LOOKUP; + sevent = (isc_socketevent_t *)event; + query = sevent->ev_arg; + + INSIST(query->waiting_connect); + + query->waiting_connect = ISC_FALSE; + + if (sevent->result == ISC_R_CANCELED) { + debug("in cancel handler"); + isc_socket_detach(&query->sock); + sockcount--; + INSIST(sockcount >= 0); + debug("sockcount=%d", sockcount); + query->waiting_connect = ISC_FALSE; + isc_event_free(&event); + l = query->lookup; + clear_query(query); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } + if (sevent->result != ISC_R_SUCCESS) { + char sockstr[ISC_SOCKADDR_FORMATSIZE]; + + debug("unsuccessful connection: %s", + isc_result_totext(sevent->result)); + isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr)); + if (sevent->result != ISC_R_CANCELED) + printf(";; Connection to %s(%s) for %s failed: " + "%s.\n", sockstr, + query->servname, query->lookup->textname, + isc_result_totext(sevent->result)); + isc_socket_detach(&query->sock); + sockcount--; + INSIST(sockcount >= 0); + /* XXX Clean up exitcodes */ + if (exitcode < 9) + exitcode = 9; + debug("sockcount=%d", sockcount); + query->waiting_connect = ISC_FALSE; + isc_event_free(&event); + l = query->lookup; + if (l->current_query != NULL) + next = ISC_LIST_NEXT(l->current_query, link); + else + next = NULL; + clear_query(query); + if (next != NULL) { + bringup_timer(next, TCP_TIMEOUT); + send_tcp_connect(next); + } else { + check_next_lookup(l); + } + UNLOCK_LOOKUP; + return; + } + launch_next_query(query, ISC_TRUE); + isc_event_free(&event); + UNLOCK_LOOKUP; +} + +/*% + * Check if the ongoing XFR needs more data before it's complete, using + * the semantics of IXFR and AXFR protocols. Much of the complexity of + * this routine comes from determining when an IXFR is complete. + * ISC_FALSE means more data is on the way, and the recv has been issued. + */ +static isc_boolean_t +check_for_more_data(dig_query_t *query, dns_message_t *msg, + isc_socketevent_t *sevent) +{ + dns_rdataset_t *rdataset = NULL; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_soa_t soa; + isc_uint32_t serial; + isc_result_t result; + + debug("check_for_more_data()"); + + /* + * By the time we're in this routine, we know we're doing + * either an AXFR or IXFR. If there's no second_rr_type, + * then we don't yet know which kind of answer we got back + * from the server. Here, we're going to walk through the + * rr's in the message, acting as necessary whenever we hit + * an SOA rr. + */ + + query->msg_count++; + query->byte_count += sevent->n; + result = dns_message_firstname(msg, DNS_SECTION_ANSWER); + if (result != ISC_R_SUCCESS) { + puts("; Transfer failed."); + return (ISC_TRUE); + } + do { + dns_name_t *name; + name = NULL; + dns_message_currentname(msg, DNS_SECTION_ANSWER, + &name); + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) { + result = dns_rdataset_first(rdataset); + if (result != ISC_R_SUCCESS) + continue; + do { + query->rr_count++; + dns_rdata_reset(&rdata); + dns_rdataset_current(rdataset, &rdata); + /* + * If this is the first rr, make sure + * it's an SOA + */ + if ((!query->first_soa_rcvd) && + (rdata.type != dns_rdatatype_soa)) { + puts("; Transfer failed. " + "Didn't start with SOA answer."); + return (ISC_TRUE); + } + if ((!query->second_rr_rcvd) && + (rdata.type != dns_rdatatype_soa)) { + query->second_rr_rcvd = ISC_TRUE; + query->second_rr_serial = 0; + debug("got the second rr as nonsoa"); + goto next_rdata; + } + + /* + * If the record is anything except an SOA + * now, just continue on... + */ + if (rdata.type != dns_rdatatype_soa) + goto next_rdata; + /* Now we have an SOA. Work with it. */ + debug("got an SOA"); + result = dns_rdata_tostruct(&rdata, &soa, NULL); + check_result(result, "dns_rdata_tostruct"); + serial = soa.serial; + dns_rdata_freestruct(&soa); + if (!query->first_soa_rcvd) { + query->first_soa_rcvd = ISC_TRUE; + query->first_rr_serial = serial; + debug("this is the first %d", + query->lookup->ixfr_serial); + if (query->lookup->ixfr_serial >= + serial) + goto doexit; + goto next_rdata; + } + if (query->lookup->rdtype == + dns_rdatatype_axfr) { + debug("doing axfr, got second SOA"); + goto doexit; + } + if (!query->second_rr_rcvd) { + if (query->first_rr_serial == serial) { + debug("doing ixfr, got " + "empty zone"); + goto doexit; + } + debug("this is the second %d", + query->lookup->ixfr_serial); + query->second_rr_rcvd = ISC_TRUE; + query->second_rr_serial = serial; + goto next_rdata; + } + if (query->second_rr_serial == 0) { + /* + * If the second RR was a non-SOA + * record, and we're getting any + * other SOA, then this is an + * AXFR, and we're done. + */ + debug("done, since axfr"); + goto doexit; + } + /* + * If we get to this point, we're doing an + * IXFR and have to start really looking + * at serial numbers. + */ + if (query->first_rr_serial == serial) { + debug("got a match for ixfr"); + if (!query->first_repeat_rcvd) { + query->first_repeat_rcvd = + ISC_TRUE; + goto next_rdata; + } + debug("done with ixfr"); + goto doexit; + } + debug("meaningless soa %d", serial); + next_rdata: + result = dns_rdataset_next(rdataset); + } while (result == ISC_R_SUCCESS); + } + result = dns_message_nextname(msg, DNS_SECTION_ANSWER); + } while (result == ISC_R_SUCCESS); + launch_next_query(query, ISC_FALSE); + return (ISC_FALSE); + doexit: + received(sevent->n, &sevent->address, query); + return (ISC_TRUE); +} + +/*% + * Event handler for recv complete. Perform whatever actions are necessary, + * based on the specifics of the user's request. + */ +static void +recv_done(isc_task_t *task, isc_event_t *event) { + isc_socketevent_t *sevent = NULL; + dig_query_t *query = NULL; + isc_buffer_t *b = NULL; + dns_message_t *msg = NULL; +#ifdef DIG_SIGCHASE + dig_message_t *chase_msg = NULL; + dig_message_t *chase_msg2 = NULL; +#endif + isc_result_t result; + dig_lookup_t *n, *l; + isc_boolean_t docancel = ISC_FALSE; + isc_boolean_t match = ISC_TRUE; + unsigned int parseflags; + dns_messageid_t id; + unsigned int msgflags; +#ifdef DIG_SIGCHASE + isc_result_t do_sigchase = ISC_FALSE; + + dns_message_t *msg_temp = NULL; + isc_region_t r; + isc_buffer_t *buf = NULL; +#endif + + UNUSED(task); + INSIST(!free_now); + + debug("recv_done()"); + + LOCK_LOOKUP; + recvcount--; + debug("recvcount=%d", recvcount); + INSIST(recvcount >= 0); + + query = event->ev_arg; + debug("lookup=%p, query=%p", query->lookup, query); + + l = query->lookup; + + REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE); + sevent = (isc_socketevent_t *)event; + + b = ISC_LIST_HEAD(sevent->bufferlist); + INSIST(b == &query->recvbuf); + ISC_LIST_DEQUEUE(sevent->bufferlist, &query->recvbuf, link); + + if ((l->tcp_mode) && (l->timer != NULL)) + isc_timer_touch(l->timer); + if ((!l->pending && !l->ns_search_only) || cancel_now) { + debug("no longer pending. Got %s", + isc_result_totext(sevent->result)); + query->waiting_connect = ISC_FALSE; + + isc_event_free(&event); + clear_query(query); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } + + if (sevent->result != ISC_R_SUCCESS) { + if (sevent->result == ISC_R_CANCELED) { + debug("in recv cancel handler"); + query->waiting_connect = ISC_FALSE; + } else { + printf(";; communications error: %s\n", + isc_result_totext(sevent->result)); + isc_socket_detach(&query->sock); + sockcount--; + debug("sockcount=%d", sockcount); + INSIST(sockcount >= 0); + } + isc_event_free(&event); + clear_query(query); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } + + if (!l->tcp_mode && + !isc_sockaddr_compare(&sevent->address, &query->sockaddr, + ISC_SOCKADDR_CMPADDR| + ISC_SOCKADDR_CMPPORT| + ISC_SOCKADDR_CMPSCOPE| + ISC_SOCKADDR_CMPSCOPEZERO)) { + char buf1[ISC_SOCKADDR_FORMATSIZE]; + char buf2[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_t any; + + if (isc_sockaddr_pf(&query->sockaddr) == AF_INET) + isc_sockaddr_any(&any); + else + isc_sockaddr_any6(&any); + + /* + * We don't expect a match when the packet is + * sent to 0.0.0.0, :: or to a multicast addresses. + * XXXMPA broadcast needs to be handled here as well. + */ + if ((!isc_sockaddr_eqaddr(&query->sockaddr, &any) && + !isc_sockaddr_ismulticast(&query->sockaddr)) || + isc_sockaddr_getport(&query->sockaddr) != + isc_sockaddr_getport(&sevent->address)) { + isc_sockaddr_format(&sevent->address, buf1, + sizeof(buf1)); + isc_sockaddr_format(&query->sockaddr, buf2, + sizeof(buf2)); + printf(";; reply from unexpected source: %s," + " expected %s\n", buf1, buf2); + match = ISC_FALSE; + } + } + + result = dns_message_peekheader(b, &id, &msgflags); + if (result != ISC_R_SUCCESS || l->sendmsg->id != id) { + match = ISC_FALSE; + if (l->tcp_mode) { + isc_boolean_t fail = ISC_TRUE; + if (result == ISC_R_SUCCESS) { + if (!query->first_soa_rcvd || + query->warn_id) + printf(";; %s: ID mismatch: " + "expected ID %u, got %u\n", + query->first_soa_rcvd ? + "WARNING" : "ERROR", + l->sendmsg->id, id); + if (query->first_soa_rcvd) + fail = ISC_FALSE; + query->warn_id = ISC_FALSE; + } else + printf(";; ERROR: short " + "(< header size) message\n"); + if (fail) { + isc_event_free(&event); + clear_query(query); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } + match = ISC_TRUE; + } else if (result == ISC_R_SUCCESS) + printf(";; Warning: ID mismatch: " + "expected ID %u, got %u\n", l->sendmsg->id, id); + else + printf(";; Warning: short " + "(< header size) message received\n"); + } + + if (result == ISC_R_SUCCESS && (msgflags & DNS_MESSAGEFLAG_QR) == 0) + printf(";; Warning: query response not set\n"); + + if (!match) + goto udp_mismatch; + + result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &msg); + check_result(result, "dns_message_create"); + + if (key != NULL) { + if (l->querysig == NULL) { + debug("getting initial querysig"); + result = dns_message_getquerytsig(l->sendmsg, mctx, + &l->querysig); + check_result(result, "dns_message_getquerytsig"); + } + result = dns_message_setquerytsig(msg, l->querysig); + check_result(result, "dns_message_setquerytsig"); + result = dns_message_settsigkey(msg, key); + check_result(result, "dns_message_settsigkey"); + msg->tsigctx = l->tsigctx; + l->tsigctx = NULL; + if (l->msgcounter != 0) + msg->tcp_continuation = 1; + l->msgcounter++; + } + + debug("before parse starts"); + parseflags = DNS_MESSAGEPARSE_PRESERVEORDER; +#ifdef DIG_SIGCHASE + if (!l->sigchase) { + do_sigchase = ISC_FALSE; + } else { + parseflags = 0; + do_sigchase = ISC_TRUE; + } +#endif + if (l->besteffort) { + parseflags |= DNS_MESSAGEPARSE_BESTEFFORT; + parseflags |= DNS_MESSAGEPARSE_IGNORETRUNCATION; + } + result = dns_message_parse(msg, b, parseflags); + if (result == DNS_R_RECOVERABLE) { + printf(";; Warning: Message parser reports malformed " + "message packet.\n"); + result = ISC_R_SUCCESS; + } + if (result != ISC_R_SUCCESS) { + printf(";; Got bad packet: %s\n", isc_result_totext(result)); + hex_dump(b); + query->waiting_connect = ISC_FALSE; + dns_message_destroy(&msg); + isc_event_free(&event); + clear_query(query); + cancel_lookup(l); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } + if (msg->counts[DNS_SECTION_QUESTION] != 0) { + match = ISC_TRUE; + for (result = dns_message_firstname(msg, DNS_SECTION_QUESTION); + result == ISC_R_SUCCESS && match; + result = dns_message_nextname(msg, DNS_SECTION_QUESTION)) { + dns_name_t *name = NULL; + dns_rdataset_t *rdataset; + + dns_message_currentname(msg, DNS_SECTION_QUESTION, + &name); + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) { + if (l->rdtype != rdataset->type || + l->rdclass != rdataset->rdclass || + !dns_name_equal(l->name, name)) { + char namestr[DNS_NAME_FORMATSIZE]; + char typebuf[DNS_RDATATYPE_FORMATSIZE]; + char classbuf[DNS_RDATACLASS_FORMATSIZE]; + dns_name_format(name, namestr, + sizeof(namestr)); + dns_rdatatype_format(rdataset->type, + typebuf, + sizeof(typebuf)); + dns_rdataclass_format(rdataset->rdclass, + classbuf, + sizeof(classbuf)); + printf(";; Question section mismatch: " + "got %s/%s/%s\n", + namestr, typebuf, classbuf); + match = ISC_FALSE; + } + } + } + if (!match) { + dns_message_destroy(&msg); + if (l->tcp_mode) { + isc_event_free(&event); + clear_query(query); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } else + goto udp_mismatch; + } + } + if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0 && + !l->ignore && !l->tcp_mode) { + printf(";; Truncated, retrying in TCP mode.\n"); + n = requeue_lookup(l, ISC_TRUE); + n->tcp_mode = ISC_TRUE; + n->origin = query->lookup->origin; + dns_message_destroy(&msg); + isc_event_free(&event); + clear_query(query); + cancel_lookup(l); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } + if ((msg->rcode == dns_rcode_servfail && !l->servfail_stops) || + (check_ra && (msg->flags & DNS_MESSAGEFLAG_RA) == 0 && l->recurse)) + { + dig_query_t *next = ISC_LIST_NEXT(query, link); + if (l->current_query == query) + l->current_query = NULL; + if (next != NULL) { + debug("sending query %p\n", next); + if (l->tcp_mode) + send_tcp_connect(next); + else + send_udp(next); + } + /* + * If our query is at the head of the list and there + * is no next, we're the only one left, so fall + * through to print the message. + */ + if ((ISC_LIST_HEAD(l->q) != query) || + (ISC_LIST_NEXT(query, link) != NULL)) { + if( l->comments == ISC_TRUE ) + printf(";; Got %s from %s, " + "trying next server\n", + msg->rcode == dns_rcode_servfail ? + "SERVFAIL reply" : + "recursion not available", + query->servname); + clear_query(query); + check_next_lookup(l); + dns_message_destroy(&msg); + isc_event_free(&event); + UNLOCK_LOOKUP; + return; + } + } + + if (key != NULL) { + result = dns_tsig_verify(&query->recvbuf, msg, NULL, NULL); + if (result != ISC_R_SUCCESS) { + printf(";; Couldn't verify signature: %s\n", + isc_result_totext(result)); + validated = ISC_FALSE; + } + l->tsigctx = msg->tsigctx; + msg->tsigctx = NULL; + if (l->querysig != NULL) { + debug("freeing querysig buffer %p", l->querysig); + isc_buffer_free(&l->querysig); + } + result = dns_message_getquerytsig(msg, mctx, &l->querysig); + check_result(result,"dns_message_getquerytsig"); + } + + extrabytes = isc_buffer_remaininglength(b); + + debug("after parse"); + if (l->doing_xfr && l->xfr_q == NULL) { + l->xfr_q = query; + /* + * Once we are in the XFR message, increase + * the timeout to much longer, so brief network + * outages won't cause the XFR to abort + */ + if (timeout != INT_MAX && l->timer != NULL) { + unsigned int local_timeout; + + if (timeout == 0) { + if (l->tcp_mode) + local_timeout = TCP_TIMEOUT * 4; + else + local_timeout = UDP_TIMEOUT * 4; + } else { + if (timeout < (INT_MAX / 4)) + local_timeout = timeout * 4; + else + local_timeout = INT_MAX; + } + debug("have local timeout of %d", local_timeout); + isc_interval_set(&l->interval, local_timeout, 0); + result = isc_timer_reset(l->timer, + isc_timertype_once, + NULL, + &l->interval, + ISC_FALSE); + check_result(result, "isc_timer_reset"); + } + } + + if (!l->doing_xfr || l->xfr_q == query) { + if (msg->rcode != dns_rcode_noerror && + (l->origin != NULL || l->need_search)) { + if (!next_origin(msg, query) || showsearch) { + printmessage(query, msg, ISC_TRUE); + received(b->used, &sevent->address, query); + } + } else if (!l->trace && !l->ns_search_only) { +#ifdef DIG_SIGCHASE + if (!do_sigchase) +#endif + printmessage(query, msg, ISC_TRUE); + } else if (l->trace) { + int n = 0; + int count = msg->counts[DNS_SECTION_ANSWER]; + + debug("in TRACE code"); + if (!l->ns_search_only) + printmessage(query, msg, ISC_TRUE); + + l->rdtype = l->qrdtype; + if (l->trace_root || (l->ns_search_only && count > 0)) { + if (!l->trace_root) + l->rdtype = dns_rdatatype_soa; + n = followup_lookup(msg, query, + DNS_SECTION_ANSWER); + l->trace_root = ISC_FALSE; + } else if (count == 0) + n = followup_lookup(msg, query, + DNS_SECTION_AUTHORITY); + if (n == 0) + docancel = ISC_TRUE; + } else { + debug("in NSSEARCH code"); + + if (l->trace_root) { + /* + * This is the initial NS query. + */ + int n; + + l->rdtype = dns_rdatatype_soa; + n = followup_lookup(msg, query, + DNS_SECTION_ANSWER); + if (n == 0) + docancel = ISC_TRUE; + l->trace_root = ISC_FALSE; + } else +#ifdef DIG_SIGCHASE + if (!do_sigchase) +#endif + printmessage(query, msg, ISC_TRUE); + } +#ifdef DIG_SIGCHASE + if (do_sigchase) { + chase_msg = isc_mem_allocate(mctx, + sizeof(dig_message_t)); + if (chase_msg == NULL) { + fatal("Memory allocation failure in %s:%d", + __FILE__, __LINE__); + } + ISC_LIST_INITANDAPPEND(chase_message_list, chase_msg, + link); + if (dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, + &msg_temp) != ISC_R_SUCCESS) { + fatal("dns_message_create in %s:%d", + __FILE__, __LINE__); + } + + isc_buffer_usedregion(b, &r); + result = isc_buffer_allocate(mctx, &buf, r.length); + + check_result(result, "isc_buffer_allocate"); + result = isc_buffer_copyregion(buf, &r); + check_result(result, "isc_buffer_copyregion"); + + result = dns_message_parse(msg_temp, buf, 0); + + isc_buffer_free(&buf); + chase_msg->msg = msg_temp; + + chase_msg2 = isc_mem_allocate(mctx, + sizeof(dig_message_t)); + if (chase_msg2 == NULL) { + fatal("Memory allocation failure in %s:%d", + __FILE__, __LINE__); + } + ISC_LIST_INITANDAPPEND(chase_message_list2, chase_msg2, + link); + chase_msg2->msg = msg; + } +#endif + } + +#ifdef DIG_SIGCHASE + if (l->sigchase && ISC_LIST_EMPTY(lookup_list)) { + sigchase(msg_temp); + } +#endif + + if (l->pending) + debug("still pending."); + if (l->doing_xfr) { + if (query != l->xfr_q) { + dns_message_destroy(&msg); + isc_event_free(&event); + query->waiting_connect = ISC_FALSE; + UNLOCK_LOOKUP; + return; + } + if (!docancel) + docancel = check_for_more_data(query, msg, sevent); + if (docancel) { + dns_message_destroy(&msg); + clear_query(query); + cancel_lookup(l); + check_next_lookup(l); + } + } else { + + if (msg->rcode == dns_rcode_noerror || l->origin == NULL) { + +#ifdef DIG_SIGCHASE + if (!l->sigchase) +#endif + received(b->used, &sevent->address, query); + } + + if (!query->lookup->ns_search_only) + query->lookup->pending = ISC_FALSE; + if (!query->lookup->ns_search_only || + query->lookup->trace_root || docancel) { +#ifdef DIG_SIGCHASE + if (!do_sigchase) +#endif + dns_message_destroy(&msg); + + cancel_lookup(l); + } + clear_query(query); + check_next_lookup(l); + } + if (msg != NULL) { +#ifdef DIG_SIGCHASE + if (do_sigchase) + msg = NULL; + else +#endif + dns_message_destroy(&msg); + } + isc_event_free(&event); + UNLOCK_LOOKUP; + return; + + udp_mismatch: + isc_buffer_invalidate(&query->recvbuf); + isc_buffer_init(&query->recvbuf, query->recvspace, COMMSIZE); + ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf, link); + result = isc_socket_recvv(query->sock, &query->recvlist, 1, + global_task, recv_done, query); + check_result(result, "isc_socket_recvv"); + recvcount++; + isc_event_free(&event); + UNLOCK_LOOKUP; + return; +} + +/*% + * Turn a name into an address, using system-supplied routines. This is + * used in looking up server names, etc... and needs to use system-supplied + * routines, since they may be using a non-DNS system for these lookups. + */ +isc_result_t +get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) { + int count; + isc_result_t result; + + isc_app_block(); + result = bind9_getaddresses(host, port, sockaddr, 1, &count); + isc_app_unblock(); + if (result != ISC_R_SUCCESS) + return (result); + + INSIST(count == 1); + + return (ISC_R_SUCCESS); +} + +/*% + * Initiate either a TCP or UDP lookup + */ +void +do_lookup(dig_lookup_t *lookup) { + + REQUIRE(lookup != NULL); + + debug("do_lookup()"); + lookup->pending = ISC_TRUE; + if (lookup->tcp_mode) + send_tcp_connect(ISC_LIST_HEAD(lookup->q)); + else + send_udp(ISC_LIST_HEAD(lookup->q)); +} + +/*% + * Start everything in action upon task startup. + */ +void +onrun_callback(isc_task_t *task, isc_event_t *event) { + UNUSED(task); + + isc_event_free(&event); + LOCK_LOOKUP; + start_lookup(); + UNLOCK_LOOKUP; +} + +/*% + * Make everything on the lookup queue go away. Mainly used by the + * SIGINT handler. + */ +void +cancel_all(void) { + dig_lookup_t *l, *n; + dig_query_t *q, *nq; + + debug("cancel_all()"); + + LOCK_LOOKUP; + if (free_now) { + UNLOCK_LOOKUP; + return; + } + cancel_now = ISC_TRUE; + if (current_lookup != NULL) { + if (current_lookup->timer != NULL) + isc_timer_detach(¤t_lookup->timer); + q = ISC_LIST_HEAD(current_lookup->q); + while (q != NULL) { + debug("canceling query %p, belonging to %p", + q, current_lookup); + nq = ISC_LIST_NEXT(q, link); + if (q->sock != NULL) { + isc_socket_cancel(q->sock, NULL, + ISC_SOCKCANCEL_ALL); + } else { + clear_query(q); + } + q = nq; + } + } + l = ISC_LIST_HEAD(lookup_list); + while (l != NULL) { + n = ISC_LIST_NEXT(l, link); + ISC_LIST_DEQUEUE(lookup_list, l, link); + try_clear_lookup(l); + l = n; + } + UNLOCK_LOOKUP; +} + +/*% + * Destroy all of the libs we are using, and get everything ready for a + * clean shutdown. + */ +void +destroy_libs(void) { +#ifdef DIG_SIGCHASE + void * ptr; + dig_message_t *chase_msg; +#endif +#ifdef WITH_IDN + isc_result_t result; +#endif + + debug("destroy_libs()"); + if (global_task != NULL) { + debug("freeing task"); + isc_task_detach(&global_task); + } + /* + * The taskmgr_destroy() call blocks until all events are cleared + * from the task. + */ + if (taskmgr != NULL) { + debug("freeing taskmgr"); + isc_taskmgr_destroy(&taskmgr); + } + LOCK_LOOKUP; + REQUIRE(sockcount == 0); + REQUIRE(recvcount == 0); + REQUIRE(sendcount == 0); + + INSIST(ISC_LIST_HEAD(lookup_list) == NULL); + INSIST(current_lookup == NULL); + INSIST(!free_now); + + free_now = ISC_TRUE; + + lwres_conf_clear(lwctx); + lwres_context_destroy(&lwctx); + + flush_server_list(); + + clear_searchlist(); + +#ifdef WITH_IDN + result = dns_name_settotextfilter(NULL); + check_result(result, "dns_name_settotextfilter"); +#endif + dns_name_destroy(); + + if (commctx != NULL) { + debug("freeing commctx"); + isc_mempool_destroy(&commctx); + } + if (socketmgr != NULL) { + debug("freeing socketmgr"); + isc_socketmgr_destroy(&socketmgr); + } + if (timermgr != NULL) { + debug("freeing timermgr"); + isc_timermgr_destroy(&timermgr); + } + if (key != NULL) { + debug("freeing key %p", key); + dns_tsigkey_detach(&key); + } + if (namebuf != NULL) + isc_buffer_free(&namebuf); + + if (is_dst_up) { + debug("destroy DST lib"); + dst_lib_destroy(); + is_dst_up = ISC_FALSE; + } + if (entp != NULL) { + debug("detach from entropy"); + isc_entropy_detach(&entp); + } + + UNLOCK_LOOKUP; + DESTROYLOCK(&lookup_lock); +#ifdef DIG_SIGCHASE + + debug("Destroy the messages kept for sigchase"); + /* Destroy the messages kept for sigchase */ + chase_msg = ISC_LIST_HEAD(chase_message_list); + + while (chase_msg != NULL) { + INSIST(chase_msg->msg != NULL); + dns_message_destroy(&(chase_msg->msg)); + ptr = chase_msg; + chase_msg = ISC_LIST_NEXT(chase_msg, link); + isc_mem_free(mctx, ptr); + } + + chase_msg = ISC_LIST_HEAD(chase_message_list2); + + while (chase_msg != NULL) { + INSIST(chase_msg->msg != NULL); + dns_message_destroy(&(chase_msg->msg)); + ptr = chase_msg; + chase_msg = ISC_LIST_NEXT(chase_msg, link); + isc_mem_free(mctx, ptr); + } + if (dns_name_dynamic(&chase_name)) + free_name(&chase_name, mctx); +#if DIG_SIGCHASE_TD + if (dns_name_dynamic(&chase_current_name)) + free_name(&chase_current_name, mctx); + if (dns_name_dynamic(&chase_authority_name)) + free_name(&chase_authority_name, mctx); +#endif +#if DIG_SIGCHASE_BU + if (dns_name_dynamic(&chase_signame)) + free_name(&chase_signame, mctx); +#endif + + debug("Destroy memory"); + +#endif + if (memdebugging != 0) + isc_mem_stats(mctx, stderr); + if (mctx != NULL) + isc_mem_destroy(&mctx); +} + +#ifdef WITH_IDN +static void +initialize_idn(void) { + idn_result_t r; + isc_result_t result; + +#ifdef HAVE_SETLOCALE + /* Set locale */ + (void)setlocale(LC_ALL, ""); +#endif + /* Create configuration context. */ + r = idn_nameinit(1); + if (r != idn_success) + fatal("idn api initialization failed: %s", + idn_result_tostring(r)); + + /* Set domain name -> text post-conversion filter. */ + result = dns_name_settotextfilter(output_filter); + check_result(result, "dns_name_settotextfilter"); +} + +static isc_result_t +output_filter(isc_buffer_t *buffer, unsigned int used_org, + isc_boolean_t absolute) +{ + char tmp1[MAXDLEN], tmp2[MAXDLEN]; + size_t fromlen, tolen; + isc_boolean_t end_with_dot; + + /* + * Copy contents of 'buffer' to 'tmp1', supply trailing dot + * if 'absolute' is true, and terminate with NUL. + */ + fromlen = isc_buffer_usedlength(buffer) - used_org; + if (fromlen >= MAXDLEN) + return (ISC_R_SUCCESS); + memcpy(tmp1, (char *)isc_buffer_base(buffer) + used_org, fromlen); + end_with_dot = (tmp1[fromlen - 1] == '.') ? ISC_TRUE : ISC_FALSE; + if (absolute && !end_with_dot) { + fromlen++; + if (fromlen >= MAXDLEN) + return (ISC_R_SUCCESS); + tmp1[fromlen - 1] = '.'; + } + tmp1[fromlen] = '\0'; + + /* + * Convert contents of 'tmp1' to local encoding. + */ + if (idn_decodename(IDN_DECODE_APP, tmp1, tmp2, MAXDLEN) != idn_success) + return (ISC_R_SUCCESS); + strcpy(tmp1, tmp2); + + /* + * Copy the converted contents in 'tmp1' back to 'buffer'. + * If we have appended trailing dot, remove it. + */ + tolen = strlen(tmp1); + if (absolute && !end_with_dot && tmp1[tolen - 1] == '.') + tolen--; + + if (isc_buffer_length(buffer) < used_org + tolen) + return (ISC_R_NOSPACE); + + isc_buffer_subtract(buffer, isc_buffer_usedlength(buffer) - used_org); + memcpy(isc_buffer_used(buffer), tmp1, tolen); + isc_buffer_add(buffer, tolen); + + return (ISC_R_SUCCESS); +} + +static idn_result_t +append_textname(char *name, const char *origin, size_t namesize) { + size_t namelen = strlen(name); + size_t originlen = strlen(origin); + + /* Already absolute? */ + if (namelen > 0 && name[namelen - 1] == '.') + return idn_success; + + /* Append dot and origin */ + + if (namelen + 1 + originlen >= namesize) + return idn_buffer_overflow; + + name[namelen++] = '.'; + (void)strcpy(name + namelen, origin); + return idn_success; +} + +static void +idn_check_result(idn_result_t r, const char *msg) { + if (r != idn_success) { + exitcode = 1; + fatal("%s: %s", msg, idn_result_tostring(r)); + } +} +#endif /* WITH_IDN */ + +#ifdef DIG_SIGCHASE +void +print_type(dns_rdatatype_t type) +{ + isc_buffer_t * b = NULL; + isc_result_t result; + isc_region_t r; + + result = isc_buffer_allocate(mctx, &b, 4000); + check_result(result, "isc_buffer_allocate"); + + result = dns_rdatatype_totext(type, b); + check_result(result, "print_type"); + + isc_buffer_usedregion(b, &r); + r.base[r.length] = '\0'; + + printf("%s", r.base); + + isc_buffer_free(&b); +} + +void +dump_database_section(dns_message_t *msg, int section) +{ + dns_name_t *msg_name=NULL; + + dns_rdataset_t *rdataset; + + do { + dns_message_currentname(msg, section, &msg_name); + + for (rdataset = ISC_LIST_HEAD(msg_name->list); rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) { + dns_name_print(msg_name, stdout); + printf("\n"); + print_rdataset(msg_name, rdataset, mctx); + printf("end\n"); + } + msg_name = NULL; + } while (dns_message_nextname(msg, section) == ISC_R_SUCCESS); +} + +void +dump_database(void) { + dig_message_t * msg; + + for (msg = ISC_LIST_HEAD(chase_message_list); msg != NULL; + msg = ISC_LIST_NEXT(msg, link)) { + if (dns_message_firstname(msg->msg, DNS_SECTION_ANSWER) + == ISC_R_SUCCESS) + dump_database_section(msg->msg, DNS_SECTION_ANSWER); + + if (dns_message_firstname(msg->msg, DNS_SECTION_AUTHORITY) + == ISC_R_SUCCESS) + dump_database_section(msg->msg, DNS_SECTION_AUTHORITY); + + if (dns_message_firstname(msg->msg, DNS_SECTION_ADDITIONAL) + == ISC_R_SUCCESS) + dump_database_section(msg->msg, DNS_SECTION_ADDITIONAL); + } +} + + +dns_rdataset_t * +search_type(dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers) { + dns_rdataset_t *rdataset; + dns_rdata_sig_t siginfo; + dns_rdata_t sigrdata = DNS_RDATA_INIT; + isc_result_t result; + + for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) { + if (type == dns_rdatatype_any) { + if (rdataset->type != dns_rdatatype_rrsig) + return (rdataset); + } else if ((type == dns_rdatatype_rrsig) && + (rdataset->type == dns_rdatatype_rrsig)) { + result = dns_rdataset_first(rdataset); + check_result(result, "empty rdataset"); + dns_rdataset_current(rdataset, &sigrdata); + result = dns_rdata_tostruct(&sigrdata, &siginfo, NULL); + check_result(result, "sigrdata tostruct siginfo"); + + if ((siginfo.covered == covers) || + (covers == dns_rdatatype_any)) { + dns_rdata_reset(&sigrdata); + dns_rdata_freestruct(&siginfo); + return (rdataset); + } + dns_rdata_reset(&sigrdata); + dns_rdata_freestruct(&siginfo); + } else if (rdataset->type == type) + return (rdataset); + } + return (NULL); +} + +dns_rdataset_t * +chase_scanname_section(dns_message_t *msg, dns_name_t *name, + dns_rdatatype_t type, dns_rdatatype_t covers, + int section) +{ + dns_rdataset_t *rdataset; + dns_name_t *msg_name = NULL; + + do { + dns_message_currentname(msg, section, &msg_name); + if (dns_name_compare(msg_name, name) == 0) { + rdataset = search_type(msg_name, type, covers); + if (rdataset != NULL) + return (rdataset); + } + msg_name = NULL; + } while (dns_message_nextname(msg, section) == ISC_R_SUCCESS); + + return (NULL); +} + + +dns_rdataset_t * +chase_scanname(dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers) +{ + dns_rdataset_t *rdataset = NULL; + dig_message_t * msg; + + for (msg = ISC_LIST_HEAD(chase_message_list2); msg != NULL; + msg = ISC_LIST_NEXT(msg, link)) { + if (dns_message_firstname(msg->msg, DNS_SECTION_ANSWER) + == ISC_R_SUCCESS) + rdataset = chase_scanname_section(msg->msg, name, + type, covers, + DNS_SECTION_ANSWER); + if (rdataset != NULL) + return (rdataset); + if (dns_message_firstname(msg->msg, DNS_SECTION_AUTHORITY) + == ISC_R_SUCCESS) + rdataset = + chase_scanname_section(msg->msg, name, + type, covers, + DNS_SECTION_AUTHORITY); + if (rdataset != NULL) + return (rdataset); + if (dns_message_firstname(msg->msg, DNS_SECTION_ADDITIONAL) + == ISC_R_SUCCESS) + rdataset = + chase_scanname_section(msg->msg, name, type, + covers, + DNS_SECTION_ADDITIONAL); + if (rdataset != NULL) + return (rdataset); + } + + return (NULL); +} + +dns_rdataset_t * +sigchase_scanname(dns_rdatatype_t type, dns_rdatatype_t covers, + isc_boolean_t * lookedup, dns_name_t *rdata_name) +{ + dig_lookup_t *lookup; + isc_buffer_t *b = NULL; + isc_region_t r; + isc_result_t result; + dns_rdataset_t * temp; + dns_rdatatype_t querytype; + + temp = chase_scanname(rdata_name, type, covers); + if (temp != NULL) + return (temp); + + if (*lookedup == ISC_TRUE) + return (NULL); + + lookup = clone_lookup(current_lookup, ISC_TRUE); + lookup->trace_root = ISC_FALSE; + lookup->new_search = ISC_TRUE; + + result = isc_buffer_allocate(mctx, &b, BUFSIZE); + check_result(result, "isc_buffer_allocate"); + result = dns_name_totext(rdata_name, ISC_FALSE, b); + check_result(result, "dns_name_totext"); + isc_buffer_usedregion(b, &r); + r.base[r.length] = '\0'; + strcpy(lookup->textname, (char*)r.base); + isc_buffer_free(&b); + + if (type == dns_rdatatype_rrsig) + querytype = covers; + else + querytype = type; + + if (querytype == 0 || querytype == 255) { + printf("Error in the queried type: %d\n", querytype); + return (NULL); + } + + lookup->rdtype = querytype; + lookup->rdtypeset = ISC_TRUE; + lookup->qrdtype = querytype; + *lookedup = ISC_TRUE; + + ISC_LIST_APPEND(lookup_list, lookup, link); + printf("\n\nLaunch a query to find a RRset of type "); + print_type(type); + printf(" for zone: %s\n", lookup->textname); + return (NULL); +} + +void +insert_trustedkey(dst_key_t * key) +{ + if (key == NULL) + return; + if (tk_list.nb_tk >= MAX_TRUSTED_KEY) + return; + + tk_list.key[tk_list.nb_tk++] = key; + return; +} + +void +clean_trustedkey() +{ + int i = 0; + + for (i= 0; i < MAX_TRUSTED_KEY; i++) { + if (tk_list.key[i] != NULL) { + dst_key_free(&tk_list.key[i]); + tk_list.key[i] = NULL; + } else + break; + } + tk_list.nb_tk = 0; + return; +} + +char alphnum[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + +isc_result_t +removetmpkey(isc_mem_t *mctx, const char *file) +{ + char *tempnamekey = NULL; + int tempnamekeylen; + isc_result_t result; + + tempnamekeylen = strlen(file)+10; + + tempnamekey = isc_mem_allocate(mctx, tempnamekeylen); + if (tempnamekey == NULL) + return (ISC_R_NOMEMORY); + + memset(tempnamekey, 0, tempnamekeylen); + + strcat(tempnamekey, file); + strcat(tempnamekey,".key"); + isc_file_remove(tempnamekey); + + result = isc_file_remove(tempnamekey); + isc_mem_free(mctx, tempnamekey); + return (result); +} + +isc_result_t +opentmpkey(isc_mem_t *mctx, const char *file, char **tempp, FILE **fp) { + FILE *f = NULL; + isc_result_t result; + char *tempname = NULL; + char *tempnamekey = NULL; + int tempnamelen; + int tempnamekeylen; + char *x; + char *cp; + isc_uint32_t which; + + while (1) { + tempnamelen = strlen(file) + 20; + tempname = isc_mem_allocate(mctx, tempnamelen); + if (tempname == NULL) + return (ISC_R_NOMEMORY); + memset(tempname, 0, tempnamelen); + + result = isc_file_mktemplate(file, tempname, tempnamelen); + if (result != ISC_R_SUCCESS) + goto cleanup; + + cp = tempname; + while (*cp != '\0') + cp++; + if (cp == tempname) { + isc_mem_free(mctx, tempname); + return (ISC_R_FAILURE); + } + + x = cp--; + while (cp >= tempname && *cp == 'X') { + isc_random_get(&which); + *cp = alphnum[which % (sizeof(alphnum) - 1)]; + x = cp--; + } + + tempnamekeylen = tempnamelen+5; + tempnamekey = isc_mem_allocate(mctx, tempnamekeylen); + if (tempnamekey == NULL) + return (ISC_R_NOMEMORY); + + memset(tempnamekey, 0, tempnamekeylen); + strncpy(tempnamekey, tempname, tempnamelen); + strcat(tempnamekey ,".key"); + + + if (isc_file_exists(tempnamekey)) { + isc_mem_free(mctx, tempnamekey); + isc_mem_free(mctx, tempname); + continue; + } + + if ((f = fopen(tempnamekey, "w")) == NULL) { + printf("get_trusted_key(): trusted key not found %s\n", + tempnamekey); + return (ISC_R_FAILURE); + } + break; + } + isc_mem_free(mctx, tempnamekey); + *tempp = tempname; + *fp = f; + return (ISC_R_SUCCESS); + + cleanup: + isc_mem_free(mctx, tempname); + + return (result); +} + + +isc_result_t +get_trusted_key(isc_mem_t *mctx) +{ + isc_result_t result; + const char *filename = NULL; + char *filetemp = NULL; + char buf[1500]; + FILE *fp, *fptemp; + dst_key_t *key = NULL; + + result = isc_file_exists(trustedkey); + if (result != ISC_TRUE) { + result = isc_file_exists("/etc/trusted-key.key"); + if (result != ISC_TRUE) { + result = isc_file_exists("./trusted-key.key"); + if (result != ISC_TRUE) + return (ISC_R_FAILURE); + else + filename = "./trusted-key.key"; + } else + filename = "/etc/trusted-key.key"; + } else + filename = trustedkey; + + if (filename == NULL) { + printf("No trusted key\n"); + return (ISC_R_FAILURE); + } + + if ((fp = fopen(filename, "r")) == NULL) { + printf("get_trusted_key(): trusted key not found %s\n", + filename); + return (ISC_R_FAILURE); + } + while (fgets(buf, sizeof(buf), fp) != NULL) { + result = opentmpkey(mctx,"tmp_file", &filetemp, &fptemp); + if (result != ISC_R_SUCCESS) { + fclose(fp); + return (ISC_R_FAILURE); + } + if (fputs(buf, fptemp) < 0) { + fclose(fp); + fclose(fptemp); + return (ISC_R_FAILURE); + } + fclose(fptemp); + result = dst_key_fromnamedfile(filetemp, DST_TYPE_PUBLIC, + mctx, &key); + removetmpkey(mctx, filetemp); + isc_mem_free(mctx, filetemp); + if (result != ISC_R_SUCCESS) { + fclose(fp); + return (ISC_R_FAILURE); + } + insert_trustedkey(key); +#if 0 + dst_key_tofile(key, DST_TYPE_PUBLIC,"/tmp"); +#endif + key = NULL; + } + return (ISC_R_SUCCESS); +} + + +static void +nameFromString(const char *str, dns_name_t *p_ret) { + size_t len = strlen(str); + isc_result_t result; + isc_buffer_t buffer; + dns_fixedname_t fixedname; + + REQUIRE(p_ret != NULL); + REQUIRE(str != NULL); + + isc_buffer_init(&buffer, str, len); + isc_buffer_add(&buffer, len); + + dns_fixedname_init(&fixedname); + result = dns_name_fromtext(dns_fixedname_name(&fixedname), &buffer, + dns_rootname, ISC_TRUE, NULL); + check_result(result, "nameFromString"); + + if (dns_name_dynamic(p_ret)) + free_name(p_ret, mctx); + + result = dns_name_dup(dns_fixedname_name(&fixedname), mctx, p_ret); + check_result(result, "nameFromString"); +} + + +#if DIG_SIGCHASE_TD +isc_result_t +prepare_lookup(dns_name_t *name) +{ + isc_result_t result; + dig_lookup_t *lookup = NULL; + dig_server_t *s; + void *ptr; + + lookup = clone_lookup(current_lookup, ISC_TRUE); + lookup->trace_root = ISC_FALSE; + lookup->new_search = ISC_TRUE; + lookup->trace_root_sigchase = ISC_FALSE; + + strncpy(lookup->textname, lookup->textnamesigchase, MXNAME); + + lookup->rdtype = lookup->rdtype_sigchase; + lookup->rdtypeset = ISC_TRUE; + lookup->qrdtype = lookup->qrdtype_sigchase; + + s = ISC_LIST_HEAD(lookup->my_server_list); + while (s != NULL) { + debug("freeing server %p belonging to %p", + s, lookup); + ptr = s; + s = ISC_LIST_NEXT(s, link); + ISC_LIST_DEQUEUE(lookup->my_server_list, + (dig_server_t *)ptr, link); + isc_mem_free(mctx, ptr); + } + + + for (result = dns_rdataset_first(chase_nsrdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(chase_nsrdataset)) { + char namestr[DNS_NAME_FORMATSIZE]; + dns_rdata_ns_t ns; + dns_rdata_t rdata = DNS_RDATA_INIT; + dig_server_t * srv = NULL; +#define __FOLLOW_GLUE__ +#ifdef __FOLLOW_GLUE__ + isc_buffer_t *b = NULL; + isc_result_t result; + isc_region_t r; + dns_rdataset_t *rdataset = NULL; + isc_boolean_t true = ISC_TRUE; +#endif + + memset(namestr, 0, DNS_NAME_FORMATSIZE); + + dns_rdataset_current(chase_nsrdataset, &rdata); + + result = dns_rdata_tostruct(&rdata, &ns, NULL); + check_result(result, "dns_rdata_tostruct"); + +#ifdef __FOLLOW_GLUE__ + + result = advanced_rrsearch(&rdataset, &ns.name, + dns_rdatatype_aaaa, + dns_rdatatype_any, &true); + if (result == ISC_R_SUCCESS) { + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) { + dns_rdata_t aaaa = DNS_RDATA_INIT; + dns_rdataset_current(rdataset, &aaaa); + + result = isc_buffer_allocate(mctx, &b, 80); + check_result(result, "isc_buffer_allocate"); + + dns_rdata_totext(&aaaa, &ns.name, b); + isc_buffer_usedregion(b, &r); + r.base[r.length] = '\0'; + strncpy(namestr, (char*)r.base, + DNS_NAME_FORMATSIZE); + isc_buffer_free(&b); + dns_rdata_reset(&aaaa); + + + srv = make_server(namestr, namestr); + + ISC_LIST_APPEND(lookup->my_server_list, + srv, link); + } + } + + rdataset = NULL; + result = advanced_rrsearch(&rdataset, &ns.name, dns_rdatatype_a, + dns_rdatatype_any, &true); + if (result == ISC_R_SUCCESS) { + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) { + dns_rdata_t a = DNS_RDATA_INIT; + dns_rdataset_current(rdataset, &a); + + result = isc_buffer_allocate(mctx, &b, 80); + check_result(result, "isc_buffer_allocate"); + + dns_rdata_totext(&a, &ns.name, b); + isc_buffer_usedregion(b, &r); + r.base[r.length] = '\0'; + strncpy(namestr, (char*)r.base, + DNS_NAME_FORMATSIZE); + isc_buffer_free(&b); + dns_rdata_reset(&a); + printf("ns name: %s\n", namestr); + + + srv = make_server(namestr, namestr); + + ISC_LIST_APPEND(lookup->my_server_list, + srv, link); + } + } +#else + + dns_name_format(&ns.name, namestr, sizeof(namestr)); + printf("ns name: "); + dns_name_print(&ns.name, stdout); + printf("\n"); + srv = make_server(namestr, namestr); + + ISC_LIST_APPEND(lookup->my_server_list, srv, link); + +#endif + dns_rdata_freestruct(&ns); + dns_rdata_reset(&rdata); + + } + + ISC_LIST_APPEND(lookup_list, lookup, link); + printf("\nLaunch a query to find a RRset of type "); + print_type(lookup->rdtype); + printf(" for zone: %s", lookup->textname); + printf(" with nameservers:"); + printf("\n"); + print_rdataset(name, chase_nsrdataset, mctx); + return (ISC_R_SUCCESS); +} + + +isc_result_t +child_of_zone(dns_name_t * name, dns_name_t * zone_name, + dns_name_t * child_name) +{ + dns_namereln_t name_reln; + int orderp; + unsigned int nlabelsp; + + name_reln = dns_name_fullcompare(name, zone_name, &orderp, &nlabelsp); + if (name_reln != dns_namereln_subdomain || + dns_name_countlabels(name) <= dns_name_countlabels(zone_name) + 1) { + printf("\n;; ERROR : "); + dns_name_print(name, stdout); + printf(" is not a subdomain of: "); + dns_name_print(zone_name, stdout); + printf(" FAILED\n\n"); + return (ISC_R_FAILURE); + } + + dns_name_getlabelsequence(name, + dns_name_countlabels(name) - + dns_name_countlabels(zone_name) -1, + dns_name_countlabels(zone_name) +1, + child_name); + return (ISC_R_SUCCESS); +} + +isc_result_t +grandfather_pb_test(dns_name_t *zone_name, dns_rdataset_t *sigrdataset) +{ + isc_result_t result; + dns_rdata_t sigrdata = DNS_RDATA_INIT; + dns_rdata_sig_t siginfo; + + result = dns_rdataset_first(sigrdataset); + check_result(result, "empty RRSIG dataset"); + dns_rdata_init(&sigrdata); + + do { + dns_rdataset_current(sigrdataset, &sigrdata); + + result = dns_rdata_tostruct(&sigrdata, &siginfo, NULL); + check_result(result, "sigrdata tostruct siginfo"); + + if (dns_name_compare(&siginfo.signer, zone_name) == 0) { + dns_rdata_freestruct(&siginfo); + dns_rdata_reset(&sigrdata); + return (ISC_R_SUCCESS); + } + + dns_rdata_freestruct(&siginfo); + dns_rdata_reset(&sigrdata); + + } while (dns_rdataset_next(chase_sigkeyrdataset) == ISC_R_SUCCESS); + + dns_rdata_reset(&sigrdata); + + return (ISC_R_FAILURE); +} + + +isc_result_t +initialization(dns_name_t *name) +{ + isc_result_t result; + isc_boolean_t true = ISC_TRUE; + + chase_nsrdataset = NULL; + result = advanced_rrsearch(&chase_nsrdataset, name, dns_rdatatype_ns, + dns_rdatatype_any, &true); + if (result != ISC_R_SUCCESS) { + printf("\n;; NS RRset is missing to continue validation:" + " FAILED\n\n"); + return (ISC_R_FAILURE); + } + INSIST(chase_nsrdataset != NULL); + prepare_lookup(name); + + dup_name(name, &chase_current_name, mctx); + + return (ISC_R_SUCCESS); +} +#endif + +void +print_rdataset(dns_name_t *name, dns_rdataset_t *rdataset, isc_mem_t *mctx) +{ + isc_buffer_t *b = NULL; + isc_result_t result; + isc_region_t r; + + result = isc_buffer_allocate(mctx, &b, 9000); + check_result(result, "isc_buffer_allocate"); + + printrdataset(name, rdataset, b); + + isc_buffer_usedregion(b, &r); + r.base[r.length] = '\0'; + + + printf("%s\n", r.base); + + isc_buffer_free(&b); +} + + +void +dup_name(dns_name_t *source, dns_name_t *target, isc_mem_t *mctx) { + isc_result_t result; + + if (dns_name_dynamic(target)) + free_name(target, mctx); + result = dns_name_dup(source, mctx, target); + check_result(result, "dns_name_dup"); +} + +void +free_name(dns_name_t *name, isc_mem_t *mctx) { + dns_name_free(name, mctx); + dns_name_init(name, NULL); +} + +/* + * + * take a DNSKEY RRset and the RRSIG RRset corresponding in parameter + * return ISC_R_SUCCESS if the DNSKEY RRset contains a trusted_key + * and the RRset is valid + * return ISC_R_NOTFOUND if not contains trusted key + or if the RRset isn't valid + * return ISC_R_FAILURE if problem + * + */ +isc_result_t +contains_trusted_key(dns_name_t *name, dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset, + isc_mem_t *mctx) +{ + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; + dst_key_t *trustedKey = NULL; + dst_key_t *dnsseckey = NULL; + int i; + + if (name == NULL || rdataset == NULL) + return (ISC_R_FAILURE); + + result = dns_rdataset_first(rdataset); + check_result(result, "empty rdataset"); + + do { + dns_rdataset_current(rdataset, &rdata); + INSIST(rdata.type == dns_rdatatype_dnskey); + + result = dns_dnssec_keyfromrdata(name, &rdata, + mctx, &dnsseckey); + check_result(result, "dns_dnssec_keyfromrdata"); + + + for (i = 0; i < tk_list.nb_tk; i++) { + if (dst_key_compare(tk_list.key[i], dnsseckey) + == ISC_TRUE) { + dns_rdata_reset(&rdata); + + printf(";; Ok, find a Trusted Key in the " + "DNSKEY RRset: %d\n", + dst_key_id(dnsseckey)); + if (sigchase_verify_sig_key(name, rdataset, + dnsseckey, + sigrdataset, + mctx) + == ISC_R_SUCCESS) { + dst_key_free(&dnsseckey); + dnsseckey = NULL; + return (ISC_R_SUCCESS); + } + } + } + + dns_rdata_reset(&rdata); + if (dnsseckey != NULL) + dst_key_free(&dnsseckey); + } while (dns_rdataset_next(rdataset) == ISC_R_SUCCESS); + + if (trustedKey != NULL) + dst_key_free(&trustedKey); + trustedKey = NULL; + + return (ISC_R_NOTFOUND); +} + +isc_result_t +sigchase_verify_sig(dns_name_t *name, dns_rdataset_t *rdataset, + dns_rdataset_t *keyrdataset, + dns_rdataset_t *sigrdataset, + isc_mem_t *mctx) +{ + isc_result_t result; + dns_rdata_t keyrdata = DNS_RDATA_INIT; + dst_key_t *dnsseckey = NULL; + + result = dns_rdataset_first(keyrdataset); + check_result(result, "empty DNSKEY dataset"); + dns_rdata_init(&keyrdata); + + do { + dns_rdataset_current(keyrdataset, &keyrdata); + INSIST(keyrdata.type == dns_rdatatype_dnskey); + + result = dns_dnssec_keyfromrdata(name, &keyrdata, + mctx, &dnsseckey); + check_result(result, "dns_dnssec_keyfromrdata"); + + result = sigchase_verify_sig_key(name, rdataset, dnsseckey, + sigrdataset, mctx); + if (result == ISC_R_SUCCESS) { + dns_rdata_reset(&keyrdata); + dst_key_free(&dnsseckey); + return (ISC_R_SUCCESS); + } + dst_key_free(&dnsseckey); + dns_rdata_reset(&keyrdata); + } while (dns_rdataset_next(chase_keyrdataset) == ISC_R_SUCCESS); + + dns_rdata_reset(&keyrdata); + + return (ISC_R_NOTFOUND); +} + +isc_result_t +sigchase_verify_sig_key(dns_name_t *name, dns_rdataset_t *rdataset, + dst_key_t *dnsseckey, dns_rdataset_t *sigrdataset, + isc_mem_t *mctx) +{ + isc_result_t result; + dns_rdata_t sigrdata = DNS_RDATA_INIT; + dns_rdata_sig_t siginfo; + + result = dns_rdataset_first(sigrdataset); + check_result(result, "empty RRSIG dataset"); + dns_rdata_init(&sigrdata); + + do { + dns_rdataset_current(sigrdataset, &sigrdata); + + result = dns_rdata_tostruct(&sigrdata, &siginfo, NULL); + check_result(result, "sigrdata tostruct siginfo"); + + /* + * Test if the id of the DNSKEY is + * the id of the DNSKEY signer's + */ + if (siginfo.keyid == dst_key_id(dnsseckey)) { + + result = dns_rdataset_first(rdataset); + check_result(result, "empty DS dataset"); + + result = dns_dnssec_verify(name, rdataset, dnsseckey, + ISC_FALSE, mctx, &sigrdata); + + printf(";; VERIFYING "); + print_type(rdataset->type); + printf(" RRset for "); + dns_name_print(name, stdout); + printf(" with DNSKEY:%d: %s\n", dst_key_id(dnsseckey), + isc_result_totext(result)); + + if (result == ISC_R_SUCCESS) { + dns_rdata_reset(&sigrdata); + return (result); + } + } + dns_rdata_freestruct(&siginfo); + dns_rdata_reset(&sigrdata); + + } while (dns_rdataset_next(chase_sigkeyrdataset) == ISC_R_SUCCESS); + + dns_rdata_reset(&sigrdata); + + return (ISC_R_NOTFOUND); +} + + +isc_result_t +sigchase_verify_ds(dns_name_t *name, dns_rdataset_t *keyrdataset, + dns_rdataset_t *dsrdataset, isc_mem_t *mctx) +{ + isc_result_t result; + dns_rdata_t keyrdata = DNS_RDATA_INIT; + dns_rdata_t newdsrdata = DNS_RDATA_INIT; + dns_rdata_t dsrdata = DNS_RDATA_INIT; + dns_rdata_ds_t dsinfo; + dst_key_t *dnsseckey = NULL; + unsigned char dsbuf[DNS_DS_BUFFERSIZE]; + + result = dns_rdataset_first(dsrdataset); + check_result(result, "empty DSset dataset"); + do { + dns_rdataset_current(dsrdataset, &dsrdata); + + result = dns_rdata_tostruct(&dsrdata, &dsinfo, NULL); + check_result(result, "dns_rdata_tostruct for DS"); + + result = dns_rdataset_first(keyrdataset); + check_result(result, "empty KEY dataset"); + + do { + dns_rdataset_current(keyrdataset, &keyrdata); + INSIST(keyrdata.type == dns_rdatatype_dnskey); + + result = dns_dnssec_keyfromrdata(name, &keyrdata, + mctx, &dnsseckey); + check_result(result, "dns_dnssec_keyfromrdata"); + + /* + * Test if the id of the DNSKEY is the + * id of DNSKEY referenced by the DS + */ + if (dsinfo.key_tag == dst_key_id(dnsseckey)) { + + result = dns_ds_buildrdata(name, &keyrdata, + dsinfo.digest_type, + dsbuf, &newdsrdata); + dns_rdata_freestruct(&dsinfo); + + if (result != ISC_R_SUCCESS) { + dns_rdata_reset(&keyrdata); + dns_rdata_reset(&newdsrdata); + dns_rdata_reset(&dsrdata); + dst_key_free(&dnsseckey); + dns_rdata_freestruct(&dsinfo); + printf("Oops: impossible to build" + " new DS rdata\n"); + return (result); + } + + + if (dns_rdata_compare(&dsrdata, + &newdsrdata) == 0) { + printf(";; OK a DS valids a DNSKEY" + " in the RRset\n"); + printf(";; Now verify that this" + " DNSKEY validates the " + "DNSKEY RRset\n"); + + result = sigchase_verify_sig_key(name, + keyrdataset, + dnsseckey, + chase_sigkeyrdataset, + mctx); + if (result == ISC_R_SUCCESS) { + dns_rdata_reset(&keyrdata); + dns_rdata_reset(&newdsrdata); + dns_rdata_reset(&dsrdata); + dst_key_free(&dnsseckey); + + return (result); + } + } else { + printf(";; This DS is NOT the DS for" + " the chasing KEY: FAILED\n"); + } + + dns_rdata_reset(&newdsrdata); + } + dst_key_free(&dnsseckey); + dns_rdata_reset(&keyrdata); + dnsseckey = NULL; + } while (dns_rdataset_next(chase_keyrdataset) == ISC_R_SUCCESS); + dns_rdata_reset(&dsrdata); + + } while (dns_rdataset_next(chase_dsrdataset) == ISC_R_SUCCESS); + + dns_rdata_reset(&keyrdata); + dns_rdata_reset(&newdsrdata); + dns_rdata_reset(&dsrdata); + + return (ISC_R_NOTFOUND); +} + +/* + * + * take a pointer on a rdataset in parameter and try to resolv it. + * the searched rrset is a rrset on 'name' with type 'type' + * (and if the type is a rrsig the signature cover 'covers'). + * the lookedup is to known if you have already done the query on the net. + * ISC_R_SUCCESS: if we found the rrset + * ISC_R_NOTFOUND: we do not found the rrset in cache + * and we do a query on the net + * ISC_R_FAILURE: rrset not found + */ +isc_result_t +advanced_rrsearch(dns_rdataset_t **rdataset, dns_name_t *name, + dns_rdatatype_t type, dns_rdatatype_t covers, + isc_boolean_t *lookedup) +{ + isc_boolean_t tmplookedup; + + INSIST(rdataset != NULL); + + if (*rdataset != NULL) + return (ISC_R_SUCCESS); + + tmplookedup = *lookedup; + if ((*rdataset = sigchase_scanname(type, covers, + lookedup, name)) == NULL) { + if (tmplookedup) + return (ISC_R_FAILURE); + return (ISC_R_NOTFOUND); + } + *lookedup = ISC_FALSE; + return (ISC_R_SUCCESS); +} + + + +#if DIG_SIGCHASE_TD +void +sigchase_td(dns_message_t *msg) +{ + isc_result_t result; + dns_name_t *name = NULL; + isc_boolean_t have_answer = ISC_FALSE; + isc_boolean_t true = ISC_TRUE; + + if ((result = dns_message_firstname(msg, DNS_SECTION_ANSWER)) + == ISC_R_SUCCESS) { + dns_message_currentname(msg, DNS_SECTION_ANSWER, &name); + if (current_lookup->trace_root_sigchase) { + initialization(name); + return; + } + have_answer = true; + } else { + if (!current_lookup->trace_root_sigchase) { + result = dns_message_firstname(msg, + DNS_SECTION_AUTHORITY); + if (result == ISC_R_SUCCESS) + dns_message_currentname(msg, + DNS_SECTION_AUTHORITY, + &name); + chase_nsrdataset + = chase_scanname_section(msg, name, + dns_rdatatype_ns, + dns_rdatatype_any, + DNS_SECTION_AUTHORITY); + dup_name(name, &chase_authority_name, mctx); + if (chase_nsrdataset != NULL) { + have_delegation_ns = ISC_TRUE; + printf("no response but there is a delegation" + " in authority section:"); + dns_name_print(name, stdout); + printf("\n"); + } else { + printf("no response and no delegation in " + "authority section but a reference" + " to: "); + dns_name_print(name, stdout); + printf("\n"); + error_message = msg; + } + } else { + printf(";; NO ANSWERS: %s\n", + isc_result_totext(result)); + free_name(&chase_name, mctx); + clean_trustedkey(); + return; + } + } + + + if (have_answer) { + chase_rdataset + = chase_scanname_section(msg, &chase_name, + current_lookup + ->rdtype_sigchase, + dns_rdatatype_any, + DNS_SECTION_ANSWER); + if (chase_rdataset != NULL) + have_response = ISC_TRUE; + } + + result = advanced_rrsearch(&chase_keyrdataset, + &chase_current_name, + dns_rdatatype_dnskey, + dns_rdatatype_any, + &chase_keylookedup); + if (result == ISC_R_FAILURE) { + printf("\n;; DNSKEY is missing to continue validation:" + " FAILED\n\n"); + goto cleanandgo; + } + if (result == ISC_R_NOTFOUND) + return; + INSIST(chase_keyrdataset != NULL); + printf("\n;; DNSKEYset:\n"); + print_rdataset(&chase_current_name , chase_keyrdataset, mctx); + + + result = advanced_rrsearch(&chase_sigkeyrdataset, + &chase_current_name, + dns_rdatatype_rrsig, + dns_rdatatype_dnskey, + &chase_sigkeylookedup); + if (result == ISC_R_FAILURE) { + printf("\n;; RRSIG of DNSKEY is missing to continue validation:" + " FAILED\n\n"); + goto cleanandgo; + } + if (result == ISC_R_NOTFOUND) + return; + INSIST(chase_sigkeyrdataset != NULL); + printf("\n;; RRSIG of the DNSKEYset:\n"); + print_rdataset(&chase_current_name , chase_sigkeyrdataset, mctx); + + + if (!chase_dslookedup && !chase_nslookedup) { + if (!delegation_follow) { + result = contains_trusted_key(&chase_current_name, + chase_keyrdataset, + chase_sigkeyrdataset, + mctx); + } else { + INSIST(chase_dsrdataset != NULL); + INSIST(chase_sigdsrdataset != NULL); + result = sigchase_verify_ds(&chase_current_name, + chase_keyrdataset, + chase_dsrdataset, + mctx); + } + + if (result != ISC_R_SUCCESS) { + printf("\n;; chain of trust can't be validated:" + " FAILED\n\n"); + goto cleanandgo; + } else { + chase_dsrdataset = NULL; + chase_sigdsrdataset = NULL; + } + } + + if (have_response || (!have_delegation_ns && !have_response)) { + /* test if it's a grand father case */ + + if (have_response) { + result = advanced_rrsearch(&chase_sigrdataset, + &chase_name, + dns_rdatatype_rrsig, + current_lookup + ->rdtype_sigchase, + &true); + if (result == ISC_R_FAILURE) { + printf("\n;; RRset is missing to continue" + " validation SHOULD NOT APPEND:" + " FAILED\n\n"); + goto cleanandgo; + } + + } else { + result = advanced_rrsearch(&chase_sigrdataset, + &chase_authority_name, + dns_rdatatype_rrsig, + dns_rdatatype_any, + &true); + if (result == ISC_R_FAILURE) { + printf("\n;; RRSIG is missing to continue" + " validation SHOULD NOT APPEND:" + " FAILED\n\n"); + goto cleanandgo; + } + } + result = grandfather_pb_test(&chase_current_name, + chase_sigrdataset); + if (result != ISC_R_SUCCESS) { + dns_name_t tmp_name; + + printf("\n;; We are in a Grand Father Problem:" + " See 2.2.1 in RFC 3568\n"); + chase_rdataset = NULL; + chase_sigrdataset = NULL; + have_response = ISC_FALSE; + have_delegation_ns = ISC_FALSE; + + dns_name_init(&tmp_name, NULL); + result = child_of_zone(&chase_name, &chase_current_name, + &tmp_name); + if (dns_name_dynamic(&chase_authority_name)) + free_name(&chase_authority_name, mctx); + dup_name(&tmp_name, &chase_authority_name, mctx); + printf(";; and we try to continue chain of trust" + " validation of the zone: "); + dns_name_print(&chase_authority_name, stdout); + printf("\n"); + have_delegation_ns = ISC_TRUE; + } else { + if (have_response) + goto finalstep; + else + chase_sigrdataset = NULL; + } + } + + if (have_delegation_ns) { + chase_nsrdataset = NULL; + result = advanced_rrsearch(&chase_nsrdataset, + &chase_authority_name, + dns_rdatatype_ns, + dns_rdatatype_any, + &chase_nslookedup); + if (result == ISC_R_FAILURE) { + printf("\n;;NSset is missing to continue validation:" + " FAILED\n\n"); + goto cleanandgo; + } + if (result == ISC_R_NOTFOUND) { + return; + } + INSIST(chase_nsrdataset != NULL); + + result = advanced_rrsearch(&chase_dsrdataset, + &chase_authority_name, + dns_rdatatype_ds, + dns_rdatatype_any, + &chase_dslookedup); + if (result == ISC_R_FAILURE) { + printf("\n;; DSset is missing to continue validation:" + " FAILED\n\n"); + goto cleanandgo; + } + if (result == ISC_R_NOTFOUND) + return; + INSIST(chase_dsrdataset != NULL); + printf("\n;; DSset:\n"); + print_rdataset(&chase_authority_name , chase_dsrdataset, mctx); + + result = advanced_rrsearch(&chase_sigdsrdataset, + &chase_authority_name, + dns_rdatatype_rrsig, + dns_rdatatype_ds, + &true); + if (result != ISC_R_SUCCESS) { + printf("\n;; DSset is missing to continue validation:" + " FAILED\n\n"); + goto cleanandgo; + } + printf("\n;; RRSIGset of DSset\n"); + print_rdataset(&chase_authority_name, + chase_sigdsrdataset, mctx); + INSIST(chase_sigdsrdataset != NULL); + + result = sigchase_verify_sig(&chase_authority_name, + chase_dsrdataset, + chase_keyrdataset, + chase_sigdsrdataset, mctx); + if (result != ISC_R_SUCCESS) { + printf("\n;; Impossible to verify the DSset:" + " FAILED\n\n"); + goto cleanandgo; + } + chase_keyrdataset = NULL; + chase_sigkeyrdataset = NULL; + + + prepare_lookup(&chase_authority_name); + + have_response = ISC_FALSE; + have_delegation_ns = ISC_FALSE; + delegation_follow = ISC_TRUE; + error_message = NULL; + dup_name(&chase_authority_name, &chase_current_name, mctx); + free_name(&chase_authority_name, mctx); + return; + } + + + if (error_message != NULL) { + dns_rdataset_t *rdataset; + dns_rdataset_t *sigrdataset; + dns_name_t rdata_name; + isc_result_t ret = ISC_R_FAILURE; + + dns_name_init(&rdata_name, NULL); + result = prove_nx(error_message, &chase_name, + current_lookup->rdclass_sigchase, + current_lookup->rdtype_sigchase, &rdata_name, + &rdataset, &sigrdataset); + if (rdataset == NULL || sigrdataset == NULL || + dns_name_countlabels(&rdata_name) == 0) { + printf("\n;; Impossible to verify the non-existence," + " the NSEC RRset can't be validated:" + " FAILED\n\n"); + goto cleanandgo; + } + ret = sigchase_verify_sig(&rdata_name, rdataset, + chase_keyrdataset, + sigrdataset, mctx); + if (ret != ISC_R_SUCCESS) { + free_name(&rdata_name, mctx); + printf("\n;; Impossible to verify the NSEC RR to prove" + " the non-existence : FAILED\n\n"); + goto cleanandgo; + } + free_name(&rdata_name, mctx); + if (result != ISC_R_SUCCESS) { + printf("\n;; Impossible to verify the non-existence:" + " FAILED\n\n"); + goto cleanandgo; + } else { + printf("\n;; OK the query doesn't have response but" + " we have validate this fact : SUCCESS\n\n"); + goto cleanandgo; + } + } + + cleanandgo: + printf(";; cleanandgo \n"); + if (dns_name_dynamic(&chase_current_name)) + free_name(&chase_current_name, mctx); + if (dns_name_dynamic(&chase_authority_name)) + free_name(&chase_authority_name, mctx); + clean_trustedkey(); + return; + + finalstep : + result = advanced_rrsearch(&chase_rdataset, &chase_name, + current_lookup->rdtype_sigchase, + dns_rdatatype_any , + &true); + if (result == ISC_R_FAILURE) { + printf("\n;; RRsig of RRset is missing to continue validation" + " SHOULD NOT APPEND: FAILED\n\n"); + goto cleanandgo; + } + result = sigchase_verify_sig(&chase_name, chase_rdataset, + chase_keyrdataset, + chase_sigrdataset, mctx); + if (result != ISC_R_SUCCESS) { + printf("\n;; Impossible to verify the RRset : FAILED\n\n"); + /* + printf("RRset:\n"); + print_rdataset(&chase_name , chase_rdataset, mctx); + printf("DNSKEYset:\n"); + print_rdataset(&chase_name , chase_keyrdataset, mctx); + printf("RRSIG of RRset:\n"); + print_rdataset(&chase_name , chase_sigrdataset, mctx); + printf("\n"); + */ + goto cleanandgo; + } else { + printf("\n;; The Answer:\n"); + print_rdataset(&chase_name , chase_rdataset, mctx); + + printf("\n;; FINISH : we have validate the DNSSEC chain" + " of trust: SUCCESS\n\n"); + goto cleanandgo; + } +} + +#endif + + +#if DIG_SIGCHASE_BU + +isc_result_t +getneededrr(dns_message_t *msg) +{ + isc_result_t result; + dns_name_t *name = NULL; + dns_rdata_t sigrdata = DNS_RDATA_INIT; + dns_rdata_sig_t siginfo; + isc_boolean_t true = ISC_TRUE; + + if ((result = dns_message_firstname(msg, DNS_SECTION_ANSWER)) + != ISC_R_SUCCESS) { + printf(";; NO ANSWERS: %s\n", isc_result_totext(result)); + + if (chase_name.ndata == NULL) + return (ISC_R_ADDRNOTAVAIL); + } else { + dns_message_currentname(msg, DNS_SECTION_ANSWER, &name); + } + + /* What do we chase? */ + if (chase_rdataset == NULL) { + result = advanced_rrsearch(&chase_rdataset, name, + dns_rdatatype_any, + dns_rdatatype_any, &true); + if (result != ISC_R_SUCCESS) { + printf("\n;; No Answers: Validation FAILED\n\n"); + return (ISC_R_NOTFOUND); + } + dup_name(name, &chase_name, mctx); + printf(";; RRset to chase:\n"); + print_rdataset(&chase_name, chase_rdataset, mctx); + } + INSIST(chase_rdataset != NULL); + + + if (chase_sigrdataset == NULL) { + result = advanced_rrsearch(&chase_sigrdataset, name, + dns_rdatatype_rrsig, + chase_rdataset->type, + &chase_siglookedup); + if (result == ISC_R_FAILURE) { + printf("\n;; RRSIG is missing for continue validation:" + " FAILED\n\n"); + if (dns_name_dynamic(&chase_name)) + free_name(&chase_name, mctx); + return (ISC_R_NOTFOUND); + } + if (result == ISC_R_NOTFOUND) { + return (ISC_R_NOTFOUND); + } + printf("\n;; RRSIG of the RRset to chase:\n"); + print_rdataset(&chase_name, chase_sigrdataset, mctx); + } + INSIST(chase_sigrdataset != NULL); + + + /* first find the DNSKEY name */ + result = dns_rdataset_first(chase_sigrdataset); + check_result(result, "empty RRSIG dataset"); + dns_rdataset_current(chase_sigrdataset, &sigrdata); + result = dns_rdata_tostruct(&sigrdata, &siginfo, NULL); + check_result(result, "sigrdata tostruct siginfo"); + dup_name(&siginfo.signer, &chase_signame, mctx); + dns_rdata_freestruct(&siginfo); + dns_rdata_reset(&sigrdata); + + /* Do we have a key? */ + if (chase_keyrdataset == NULL) { + result = advanced_rrsearch(&chase_keyrdataset, + &chase_signame, + dns_rdatatype_dnskey, + dns_rdatatype_any, + &chase_keylookedup); + if (result == ISC_R_FAILURE) { + printf("\n;; DNSKEY is missing to continue validation:" + " FAILED\n\n"); + free_name(&chase_signame, mctx); + if (dns_name_dynamic(&chase_name)) + free_name(&chase_name, mctx); + return (ISC_R_NOTFOUND); + } + if (result == ISC_R_NOTFOUND) { + free_name(&chase_signame, mctx); + return (ISC_R_NOTFOUND); + } + printf("\n;; DNSKEYset that signs the RRset to chase:\n"); + print_rdataset(&chase_signame, chase_keyrdataset, mctx); + } + INSIST(chase_keyrdataset != NULL); + + if (chase_sigkeyrdataset == NULL) { + result = advanced_rrsearch(&chase_sigkeyrdataset, + &chase_signame, + dns_rdatatype_rrsig, + dns_rdatatype_dnskey, + &chase_sigkeylookedup); + if (result == ISC_R_FAILURE) { + printf("\n;; RRSIG for DNSKEY is missing to continue" + " validation : FAILED\n\n"); + free_name(&chase_signame, mctx); + if (dns_name_dynamic(&chase_name)) + free_name(&chase_name, mctx); + return (ISC_R_NOTFOUND); + } + if (result == ISC_R_NOTFOUND) { + free_name(&chase_signame, mctx); + return (ISC_R_NOTFOUND); + } + printf("\n;; RRSIG of the DNSKEYset that signs the " + "RRset to chase:\n"); + print_rdataset(&chase_signame, chase_sigkeyrdataset, mctx); + } + INSIST(chase_sigkeyrdataset != NULL); + + + if (chase_dsrdataset == NULL) { + result = advanced_rrsearch(&chase_dsrdataset, &chase_signame, + dns_rdatatype_ds, + dns_rdatatype_any, + &chase_dslookedup); + if (result == ISC_R_FAILURE) { + printf("\n;; WARNING There is no DS for the zone: "); + dns_name_print(&chase_signame, stdout); + printf("\n"); + } + if (result == ISC_R_NOTFOUND) { + free_name(&chase_signame, mctx); + return (ISC_R_NOTFOUND); + } + if (chase_dsrdataset != NULL) { + printf("\n;; DSset of the DNSKEYset\n"); + print_rdataset(&chase_signame, chase_dsrdataset, mctx); + } + } + + if (chase_dsrdataset != NULL) { + /* + * if there is no RRSIG of DS, + * we don't want to search on the network + */ + result = advanced_rrsearch(&chase_sigdsrdataset, + &chase_signame, + dns_rdatatype_rrsig, + dns_rdatatype_ds, &true); + if (result == ISC_R_FAILURE) { + printf(";; WARNING : NO RRSIG DS : RRSIG DS" + " should come with DS\n"); + /* + * We continue even the DS couldn't be validated, + * because the DNSKEY could be a Trusted Key. + */ + chase_dsrdataset = NULL; + } else { + printf("\n;; RRSIG of the DSset of the DNSKEYset\n"); + print_rdataset(&chase_signame, chase_sigdsrdataset, + mctx); + } + } + return (1); +} + + + +void +sigchase_bu(dns_message_t *msg) +{ + isc_result_t result; + int ret; + + if (tk_list.nb_tk == 0) { + result = get_trusted_key(mctx); + if (result != ISC_R_SUCCESS) { + printf("No trusted keys present\n"); + return; + } + } + + + ret = getneededrr(msg); + if (ret == ISC_R_NOTFOUND) + return; + + if (ret == ISC_R_ADDRNOTAVAIL) { + /* We have no response */ + dns_rdataset_t *rdataset; + dns_rdataset_t *sigrdataset; + dns_name_t rdata_name; + dns_name_t query_name; + + + dns_name_init(&query_name, NULL); + dns_name_init(&rdata_name, NULL); + nameFromString(current_lookup->textname, &query_name); + + result = prove_nx(msg, &query_name, current_lookup->rdclass, + current_lookup->rdtype, &rdata_name, + &rdataset, &sigrdataset); + free_name(&query_name, mctx); + if (rdataset == NULL || sigrdataset == NULL || + dns_name_countlabels(&rdata_name) == 0) { + printf("\n;; Impossible to verify the Non-existence," + " the NSEC RRset can't be validated: " + "FAILED\n\n"); + clean_trustedkey(); + return; + } + + if (result != ISC_R_SUCCESS) { + printf("\n No Answers and impossible to prove the" + " unsecurity : Validation FAILED\n\n"); + clean_trustedkey(); + return; + } + printf(";; An NSEC prove the non-existence of a answers," + " Now we want validate this NSEC\n"); + + dup_name(&rdata_name, &chase_name, mctx); + free_name(&rdata_name, mctx); + chase_rdataset = rdataset; + chase_sigrdataset = sigrdataset; + chase_keyrdataset = NULL; + chase_sigkeyrdataset = NULL; + chase_dsrdataset = NULL; + chase_sigdsrdataset = NULL; + chase_siglookedup = ISC_FALSE; + chase_keylookedup = ISC_FALSE; + chase_dslookedup = ISC_FALSE; + chase_sigdslookedup = ISC_FALSE; + sigchase(msg); + clean_trustedkey(); + return; + } + + + printf("\n\n\n;; WE HAVE MATERIAL, WE NOW DO VALIDATION\n"); + + result = sigchase_verify_sig(&chase_name, chase_rdataset, + chase_keyrdataset, + chase_sigrdataset, mctx); + if (result != ISC_R_SUCCESS) { + free_name(&chase_name, mctx); + free_name(&chase_signame, mctx); + printf(";; No DNSKEY is valid to check the RRSIG" + " of the RRset: FAILED\n"); + clean_trustedkey(); + return; + } + printf(";; OK We found DNSKEY (or more) to validate the RRset\n"); + + result = contains_trusted_key(&chase_signame, chase_keyrdataset, + chase_sigkeyrdataset, mctx); + if (result == ISC_R_SUCCESS) { + free_name(&chase_name, mctx); + free_name(&chase_signame, mctx); + printf("\n;; Ok this DNSKEY is a Trusted Key," + " DNSSEC validation is ok: SUCCESS\n\n"); + clean_trustedkey(); + return; + } + + printf(";; Now, we are going to validate this DNSKEY by the DS\n"); + + if (chase_dsrdataset == NULL) { + free_name(&chase_name, mctx); + free_name(&chase_signame, mctx); + printf(";; the DNSKEY isn't trusted-key and there isn't" + " DS to validate the DNSKEY: FAILED\n"); + clean_trustedkey(); + return; + } + + result = sigchase_verify_ds(&chase_signame, chase_keyrdataset, + chase_dsrdataset, mctx); + if (result != ISC_R_SUCCESS) { + free_name(&chase_signame, mctx); + free_name(&chase_name, mctx); + printf(";; ERROR no DS validates a DNSKEY in the" + " DNSKEY RRset: FAILED\n"); + clean_trustedkey(); + return; + } else + printf(";; OK this DNSKEY (validated by the DS) validates" + " the RRset of the DNSKEYs, thus the DNSKEY validates" + " the RRset\n"); + INSIST(chase_sigdsrdataset != NULL); + + dup_name(&chase_signame, &chase_name, mctx); + free_name(&chase_signame, mctx); + chase_rdataset = chase_dsrdataset; + chase_sigrdataset = chase_sigdsrdataset; + chase_keyrdataset = NULL; + chase_sigkeyrdataset = NULL; + chase_dsrdataset = NULL; + chase_sigdsrdataset = NULL; + chase_siglookedup = chase_keylookedup = ISC_FALSE; + chase_dslookedup = chase_sigdslookedup = ISC_FALSE; + + printf(";; Now, we want to validate the DS : recursive call\n"); + sigchase(msg); + return; +} +#endif + +void +sigchase(dns_message_t *msg) { +#if DIG_SIGCHASE_TD + if (current_lookup->do_topdown) { + sigchase_td(msg); + return; + } +#endif +#if DIG_SIGCHASE_BU + sigchase_bu(msg); + return; +#endif +} + + +/* + * return 1 if name1 < name2 + * 0 if name1 == name2 + * -1 if name1 > name2 + * and -2 if problem + */ +int +inf_name(dns_name_t *name1, dns_name_t *name2) +{ + dns_label_t label1; + dns_label_t label2; + unsigned int nblabel1; + unsigned int nblabel2; + int min_lum_label; + int i; + int ret = -2; + + nblabel1 = dns_name_countlabels(name1); + nblabel2 = dns_name_countlabels(name2); + + if (nblabel1 >= nblabel2) + min_lum_label = nblabel2; + else + min_lum_label = nblabel1; + + + for (i=1 ; i < min_lum_label; i++) { + dns_name_getlabel(name1, nblabel1 -1 - i, &label1); + dns_name_getlabel(name2, nblabel2 -1 - i, &label2); + if ((ret = isc_region_compare(&label1, &label2)) != 0) { + if (ret < 0) + return (-1); + else if (ret > 0) + return (1); + } + } + if (nblabel1 == nblabel2) + return (0); + + if (nblabel1 < nblabel2) + return (-1); + else + return (1); +} + +/** + * + * + * + */ +isc_result_t +prove_nx_domain(dns_message_t *msg, + dns_name_t *name, + dns_name_t *rdata_name, + dns_rdataset_t **rdataset, + dns_rdataset_t **sigrdataset) +{ + isc_result_t ret = ISC_R_FAILURE; + isc_result_t result = ISC_R_NOTFOUND; + dns_rdataset_t *nsecset = NULL; + dns_rdataset_t *signsecset = NULL ; + dns_rdata_t nsec = DNS_RDATA_INIT; + dns_name_t *nsecname; + dns_rdata_nsec_t nsecstruct; + + if ((result = dns_message_firstname(msg, DNS_SECTION_AUTHORITY)) + != ISC_R_SUCCESS) { + printf(";; nothing in authority section : impossible to" + " validate the non-existence : FAILED\n"); + return (ISC_R_FAILURE); + } + + do { + nsecname = NULL; + dns_message_currentname(msg, DNS_SECTION_AUTHORITY, &nsecname); + nsecset = search_type(nsecname, dns_rdatatype_nsec, + dns_rdatatype_any); + if (nsecset == NULL) + continue; + + printf("There is a NSEC for this zone in the" + " AUTHORITY section:\n"); + print_rdataset(nsecname, nsecset, mctx); + + for (result = dns_rdataset_first(nsecset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(nsecset)) { + dns_rdataset_current(nsecset, &nsec); + + + signsecset + = chase_scanname_section(msg, nsecname, + dns_rdatatype_rrsig, + dns_rdatatype_nsec, + DNS_SECTION_AUTHORITY); + if (signsecset == NULL) { + printf(";; no RRSIG NSEC in authority section:" + " impossible to validate the " + "non-existence: FAILED\n"); + return (ISC_R_FAILURE); + } + + ret = dns_rdata_tostruct(&nsec, &nsecstruct, NULL); + check_result(ret,"dns_rdata_tostruct"); + + if ((inf_name(nsecname, &nsecstruct.next) == 1 && + inf_name(name, &nsecstruct.next) == 1) || + (inf_name(name, nsecname) == 1 && + inf_name(&nsecstruct.next, name) == 1)) { + dns_rdata_freestruct(&nsecstruct); + *rdataset = nsecset; + *sigrdataset = signsecset; + dup_name(nsecname, rdata_name, mctx); + + return (ISC_R_SUCCESS); + } + + dns_rdata_freestruct(&nsecstruct); + dns_rdata_reset(&nsec); + } + } while (dns_message_nextname(msg, DNS_SECTION_AUTHORITY) + == ISC_R_SUCCESS); + + *rdataset = NULL; + *sigrdataset = NULL; + rdata_name = NULL; + return (ISC_R_FAILURE); +} + +/** + * + * + * + * + * + */ +isc_result_t +prove_nx_type(dns_message_t *msg, dns_name_t *name, dns_rdataset_t *nsecset, + dns_rdataclass_t class, dns_rdatatype_t type, + dns_name_t *rdata_name, dns_rdataset_t **rdataset, + dns_rdataset_t **sigrdataset) +{ + isc_result_t ret; + dns_rdataset_t *signsecset; + dns_rdata_t nsec = DNS_RDATA_INIT; + + UNUSED(class); + + ret = dns_rdataset_first(nsecset); + check_result(ret,"dns_rdataset_first"); + + dns_rdataset_current(nsecset, &nsec); + + ret = dns_nsec_typepresent(&nsec, type); + if (ret == ISC_R_SUCCESS) + printf("OK the NSEC said that the type doesn't exist \n"); + + signsecset = chase_scanname_section(msg, name, + dns_rdatatype_rrsig, + dns_rdatatype_nsec, + DNS_SECTION_AUTHORITY); + if (signsecset == NULL) { + printf("There isn't RRSIG NSEC for the zone \n"); + return (ISC_R_FAILURE); + } + dup_name(name, rdata_name, mctx); + *rdataset = nsecset; + *sigrdataset = signsecset; + + return (ret); +} + +/** + * + * + * + * + */ +isc_result_t +prove_nx(dns_message_t *msg, dns_name_t *name, dns_rdataclass_t class, + dns_rdatatype_t type, dns_name_t *rdata_name, + dns_rdataset_t **rdataset, dns_rdataset_t **sigrdataset) +{ + isc_result_t ret; + dns_rdataset_t *nsecset = NULL; + + printf("We want to prove the non-existence of a type of rdata %d" + " or of the zone: \n", type); + + if ((ret = dns_message_firstname(msg, DNS_SECTION_AUTHORITY)) + != ISC_R_SUCCESS) { + printf(";; nothing in authority section : impossible to" + " validate the non-existence : FAILED\n"); + return (ISC_R_FAILURE); + } + + nsecset = chase_scanname_section(msg, name, dns_rdatatype_nsec, + dns_rdatatype_any, + DNS_SECTION_AUTHORITY); + if (nsecset != NULL) { + printf("We have a NSEC for this zone :OK\n"); + ret = prove_nx_type(msg, name, nsecset, class, + type, rdata_name, rdataset, + sigrdataset); + if (ret != ISC_R_SUCCESS) { + printf("prove_nx: ERROR type exist\n"); + return (ret); + } else { + printf("prove_nx: OK type does not exist\n"); + return (ISC_R_SUCCESS); + } + } else { + printf("there is no NSEC for this zone: validating " + "that the zone doesn't exist\n"); + ret = prove_nx_domain(msg, name, rdata_name, + rdataset, sigrdataset); + return (ret); + } + /* Never get here */ +} +#endif diff --git a/contrib/bind-9.5.2/bin/dig/host.1 b/contrib/bind-9.5.2/bin/dig/host.1 new file mode 100644 index 0000000000..9222ca2e22 --- /dev/null +++ b/contrib/bind-9.5.2/bin/dig/host.1 @@ -0,0 +1,219 @@ +.\" Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2000-2002 Internet Software Consortium. +.\" +.\" 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: host.1,v 1.28.164.4 2009/07/11 01:43:27 tbox Exp $ +.\" +.hy 0 +.ad l +.\" Title: host +.\" Author: +.\" Generator: DocBook XSL Stylesheets v1.71.1 +.\" Date: Jun 30, 2000 +.\" Manual: BIND9 +.\" Source: BIND9 +.\" +.TH "HOST" "1" "Jun 30, 2000" "BIND9" "BIND9" +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.SH "NAME" +host \- DNS lookup utility +.SH "SYNOPSIS" +.HP 5 +\fBhost\fR [\fB\-aCdlnrsTwv\fR] [\fB\-c\ \fR\fB\fIclass\fR\fR] [\fB\-N\ \fR\fB\fIndots\fR\fR] [\fB\-R\ \fR\fB\fInumber\fR\fR] [\fB\-t\ \fR\fB\fItype\fR\fR] [\fB\-W\ \fR\fB\fIwait\fR\fR] [\fB\-m\ \fR\fB\fIflag\fR\fR] [\fB\-4\fR] [\fB\-6\fR] {name} [server] +.SH "DESCRIPTION" +.PP +\fBhost\fR +is a simple utility for performing DNS lookups. It is normally used to convert names to IP addresses and vice versa. When no arguments or options are given, +\fBhost\fR +prints a short summary of its command line arguments and options. +.PP +\fIname\fR +is the domain name that is to be looked up. It can also be a dotted\-decimal IPv4 address or a colon\-delimited IPv6 address, in which case +\fBhost\fR +will by default perform a reverse lookup for that address. +\fIserver\fR +is an optional argument which is either the name or IP address of the name server that +\fBhost\fR +should query instead of the server or servers listed in +\fI/etc/resolv.conf\fR. +.PP +The +\fB\-a\fR +(all) option is equivalent to setting the +\fB\-v\fR +option and asking +\fBhost\fR +to make a query of type ANY. +.PP +When the +\fB\-C\fR +option is used, +\fBhost\fR +will attempt to display the SOA records for zone +\fIname\fR +from all the listed authoritative name servers for that zone. The list of name servers is defined by the NS records that are found for the zone. +.PP +The +\fB\-c\fR +option instructs to make a DNS query of class +\fIclass\fR. This can be used to lookup Hesiod or Chaosnet class resource records. The default class is IN (Internet). +.PP +Verbose output is generated by +\fBhost\fR +when the +\fB\-d\fR +or +\fB\-v\fR +option is used. The two options are equivalent. They have been provided for backwards compatibility. In previous versions, the +\fB\-d\fR +option switched on debugging traces and +\fB\-v\fR +enabled verbose output. +.PP +List mode is selected by the +\fB\-l\fR +option. This makes +\fBhost\fR +perform a zone transfer for zone +\fIname\fR. Transfer the zone printing out the NS, PTR and address records (A/AAAA). If combined with +\fB\-a\fR +all records will be printed. +.PP +The +\fB\-i\fR +option specifies that reverse lookups of IPv6 addresses should use the IP6.INT domain as defined in RFC1886. The default is to use IP6.ARPA. +.PP +The +\fB\-N\fR +option sets the number of dots that have to be in +\fIname\fR +for it to be considered absolute. The default value is that defined using the ndots statement in +\fI/etc/resolv.conf\fR, or 1 if no ndots statement is present. Names with fewer dots are interpreted as relative names and will be searched for in the domains listed in the +\fBsearch\fR +or +\fBdomain\fR +directive in +\fI/etc/resolv.conf\fR. +.PP +The number of UDP retries for a lookup can be changed with the +\fB\-R\fR +option. +\fInumber\fR +indicates how many times +\fBhost\fR +will repeat a query that does not get answered. The default number of retries is 1. If +\fInumber\fR +is negative or zero, the number of retries will default to 1. +.PP +Non\-recursive queries can be made via the +\fB\-r\fR +option. Setting this option clears the +\fBRD\fR +\(em recursion desired \(em bit in the query which +\fBhost\fR +makes. This should mean that the name server receiving the query will not attempt to resolve +\fIname\fR. The +\fB\-r\fR +option enables +\fBhost\fR +to mimic the behavior of a name server by making non\-recursive queries and expecting to receive answers to those queries that are usually referrals to other name servers. +.PP +By default, +\fBhost\fR +uses UDP when making queries. The +\fB\-T\fR +option makes it use a TCP connection when querying the name server. TCP will be automatically selected for queries that require it, such as zone transfer (AXFR) requests. +.PP +The +\fB\-4\fR +option forces +\fBhost\fR +to only use IPv4 query transport. The +\fB\-6\fR +option forces +\fBhost\fR +to only use IPv6 query transport. +.PP +The +\fB\-t\fR +option is used to select the query type. +\fItype\fR +can be any recognized query type: CNAME, NS, SOA, SIG, KEY, AXFR, etc. When no query type is specified, +\fBhost\fR +automatically selects an appropriate query type. By default, it looks for A, AAAA, and MX records, but if the +\fB\-C\fR +option was given, queries will be made for SOA records, and if +\fIname\fR +is a dotted\-decimal IPv4 address or colon\-delimited IPv6 address, +\fBhost\fR +will query for PTR records. If a query type of IXFR is chosen the starting serial number can be specified by appending an equal followed by the starting serial number (e.g. \-t IXFR=12345678). +.PP +The time to wait for a reply can be controlled through the +\fB\-W\fR +and +\fB\-w\fR +options. The +\fB\-W\fR +option makes +\fBhost\fR +wait for +\fIwait\fR +seconds. If +\fIwait\fR +is less than one, the wait interval is set to one second. When the +\fB\-w\fR +option is used, +\fBhost\fR +will effectively wait forever for a reply. The time to wait for a response will be set to the number of seconds given by the hardware's maximum value for an integer quantity. +.PP +The +\fB\-s\fR +option tells +\fBhost\fR +\fInot\fR +to send the query to the next nameserver if any server responds with a SERVFAIL response, which is the reverse of normal stub resolver behavior. +.PP +The +\fB\-m\fR +can be used to set the memory usage debugging flags +\fIrecord\fR, +\fIusage\fR +and +\fItrace\fR. +.SH "IDN SUPPORT" +.PP +If +\fBhost\fR +has been built with IDN (internationalized domain name) support, it can accept and display non\-ASCII domain names. +\fBhost\fR +appropriately converts character encoding of domain name before sending a request to DNS server or displaying a reply from the server. If you'd like to turn off the IDN support for some reason, defines the +\fBIDN_DISABLE\fR +environment variable. The IDN support is disabled if the variable is set when +\fBhost\fR +runs. +.SH "FILES" +.PP +\fI/etc/resolv.conf\fR +.SH "SEE ALSO" +.PP +\fBdig\fR(1), +\fBnamed\fR(8). +.SH "COPYRIGHT" +Copyright \(co 2004, 2005, 2007\-2009 Internet Systems Consortium, Inc. ("ISC") +.br +Copyright \(co 2000\-2002 Internet Software Consortium. +.br diff --git a/contrib/bind-9.5.2/bin/dig/host.c b/contrib/bind-9.5.2/bin/dig/host.c new file mode 100644 index 0000000000..54655e906a --- /dev/null +++ b/contrib/bind-9.5.2/bin/dig/host.c @@ -0,0 +1,878 @@ +/* + * Copyright (C) 2004-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 + * 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: host.c,v 1.116.12.3 2009/09/08 23:28:40 marka Exp $ */ + +/*! \file */ + +#include +#include +#include + +#ifdef HAVE_LOCALE_H +#include +#endif + +#ifdef WITH_IDN +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static isc_boolean_t short_form = ISC_TRUE, listed_server = ISC_FALSE; +static isc_boolean_t default_lookups = ISC_TRUE; +static int seen_error = -1; +static isc_boolean_t list_addresses = ISC_TRUE; +static dns_rdatatype_t list_type = dns_rdatatype_a; +static isc_boolean_t printed_server = ISC_FALSE; + +static const char *opcodetext[] = { + "QUERY", + "IQUERY", + "STATUS", + "RESERVED3", + "NOTIFY", + "UPDATE", + "RESERVED6", + "RESERVED7", + "RESERVED8", + "RESERVED9", + "RESERVED10", + "RESERVED11", + "RESERVED12", + "RESERVED13", + "RESERVED14", + "RESERVED15" +}; + +static const char *rcodetext[] = { + "NOERROR", + "FORMERR", + "SERVFAIL", + "NXDOMAIN", + "NOTIMP", + "REFUSED", + "YXDOMAIN", + "YXRRSET", + "NXRRSET", + "NOTAUTH", + "NOTZONE", + "RESERVED11", + "RESERVED12", + "RESERVED13", + "RESERVED14", + "RESERVED15", + "BADVERS" +}; + +struct rtype { + unsigned int type; + const char *text; +}; + +struct rtype rtypes[] = { + { 1, "has address" }, + { 2, "name server" }, + { 5, "is an alias for" }, + { 11, "has well known services" }, + { 12, "domain name pointer" }, + { 13, "host information" }, + { 15, "mail is handled by" }, + { 16, "descriptive text" }, + { 19, "x25 address" }, + { 20, "ISDN address" }, + { 24, "has signature" }, + { 25, "has key" }, + { 28, "has IPv6 address" }, + { 29, "location" }, + { 0, NULL } +}; + +static char * +rcode_totext(dns_rcode_t rcode) +{ + static char buf[sizeof("?65535")]; + union { + const char *consttext; + char *deconsttext; + } totext; + + if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) { + snprintf(buf, sizeof(buf), "?%u", rcode); + totext.deconsttext = buf; + } else + totext.consttext = rcodetext[rcode]; + return totext.deconsttext; +} + +static void +show_usage(void) { + fputs( +"Usage: host [-aCdlriTwv] [-c class] [-N ndots] [-t type] [-W time]\n" +" [-R number] [-m flag] hostname [server]\n" +" -a is equivalent to -v -t ANY\n" +" -c specifies query class for non-IN data\n" +" -C compares SOA records on authoritative nameservers\n" +" -d is equivalent to -v\n" +" -l lists all hosts in a domain, using AXFR\n" +" -i IP6.INT reverse lookups\n" +" -N changes the number of dots allowed before root lookup is done\n" +" -r disables recursive processing\n" +" -R specifies number of retries for UDP packets\n" +" -s a SERVFAIL response should stop query\n" +" -t specifies the query type\n" +" -T enables TCP/IP mode\n" +" -v enables verbose output\n" +" -w specifies to wait forever for a reply\n" +" -W specifies how long to wait for a reply\n" +" -4 use IPv4 query transport only\n" +" -6 use IPv6 query transport only\n" +" -m set memory debugging flag (trace|record|usage)\n", stderr); + exit(1); +} + +void +dighost_shutdown(void) { + isc_app_shutdown(); +} + +void +received(int bytes, isc_sockaddr_t *from, dig_query_t *query) { + isc_time_t now; + int diff; + + if (!short_form) { + char fromtext[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_format(from, fromtext, sizeof(fromtext)); + TIME_NOW(&now); + diff = (int) isc_time_microdiff(&now, &query->time_sent); + printf("Received %u bytes from %s in %d ms\n", + bytes, fromtext, diff/1000); + } +} + +void +trying(char *frm, dig_lookup_t *lookup) { + UNUSED(lookup); + + if (!short_form) + printf("Trying \"%s\"\n", frm); +} + +static void +say_message(dns_name_t *name, const char *msg, dns_rdata_t *rdata, + dig_query_t *query) +{ + isc_buffer_t *b = NULL; + char namestr[DNS_NAME_FORMATSIZE]; + isc_region_t r; + isc_result_t result; + unsigned int bufsize = BUFSIZ; + + dns_name_format(name, namestr, sizeof(namestr)); + retry: + result = isc_buffer_allocate(mctx, &b, bufsize); + check_result(result, "isc_buffer_allocate"); + result = dns_rdata_totext(rdata, NULL, b); + if (result == ISC_R_NOSPACE) { + isc_buffer_free(&b); + bufsize *= 2; + goto retry; + } + check_result(result, "dns_rdata_totext"); + isc_buffer_usedregion(b, &r); + if (query->lookup->identify_previous_line) { + printf("Nameserver %s:\n\t", + query->servname); + } + printf("%s %s %.*s", namestr, + msg, (int)r.length, (char *)r.base); + if (query->lookup->identify) { + printf(" on server %s", query->servname); + } + printf("\n"); + isc_buffer_free(&b); +} +#ifdef DIG_SIGCHASE +/* Just for compatibility : not use in host program */ +isc_result_t +printrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset, + isc_buffer_t *target) +{ + UNUSED(owner_name); + UNUSED(rdataset); + UNUSED(target); + return(ISC_FALSE); +} +#endif +static isc_result_t +printsection(dns_message_t *msg, dns_section_t sectionid, + const char *section_name, isc_boolean_t headers, + dig_query_t *query) +{ + dns_name_t *name, *print_name; + dns_rdataset_t *rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_buffer_t target; + isc_result_t result, loopresult; + isc_region_t r; + dns_name_t empty_name; + char t[4096]; + isc_boolean_t first; + isc_boolean_t no_rdata; + + if (sectionid == DNS_SECTION_QUESTION) + no_rdata = ISC_TRUE; + else + no_rdata = ISC_FALSE; + + if (headers) + printf(";; %s SECTION:\n", section_name); + + dns_name_init(&empty_name, NULL); + + result = dns_message_firstname(msg, sectionid); + if (result == ISC_R_NOMORE) + return (ISC_R_SUCCESS); + else if (result != ISC_R_SUCCESS) + return (result); + + for (;;) { + name = NULL; + dns_message_currentname(msg, sectionid, &name); + + isc_buffer_init(&target, t, sizeof(t)); + first = ISC_TRUE; + print_name = name; + + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) { + if (query->lookup->rdtype == dns_rdatatype_axfr && + !((!list_addresses && + (list_type == dns_rdatatype_any || + rdataset->type == list_type)) || + (list_addresses && + (rdataset->type == dns_rdatatype_a || + rdataset->type == dns_rdatatype_aaaa || + rdataset->type == dns_rdatatype_ns || + rdataset->type == dns_rdatatype_ptr)))) + continue; + if (!short_form) { + result = dns_rdataset_totext(rdataset, + print_name, + ISC_FALSE, + no_rdata, + &target); + if (result != ISC_R_SUCCESS) + return (result); +#ifdef USEINITALWS + if (first) { + print_name = &empty_name; + first = ISC_FALSE; + } +#else + UNUSED(first); /* Shut up compiler. */ +#endif + } else { + loopresult = dns_rdataset_first(rdataset); + while (loopresult == ISC_R_SUCCESS) { + struct rtype *t; + const char *rtt; + char typebuf[DNS_RDATATYPE_FORMATSIZE]; + char typebuf2[DNS_RDATATYPE_FORMATSIZE + + 20]; + dns_rdataset_current(rdataset, &rdata); + + for (t = rtypes; t->text != NULL; t++) { + if (t->type == rdata.type) { + rtt = t->text; + goto found; + } + } + + dns_rdatatype_format(rdata.type, + typebuf, + sizeof(typebuf)); + snprintf(typebuf2, sizeof(typebuf2), + "has %s record", typebuf); + rtt = typebuf2; + found: + say_message(print_name, rtt, + &rdata, query); + dns_rdata_reset(&rdata); + loopresult = + dns_rdataset_next(rdataset); + } + } + } + if (!short_form) { + isc_buffer_usedregion(&target, &r); + if (no_rdata) + printf(";%.*s", (int)r.length, + (char *)r.base); + else + printf("%.*s", (int)r.length, (char *)r.base); + } + + result = dns_message_nextname(msg, sectionid); + if (result == ISC_R_NOMORE) + break; + else if (result != ISC_R_SUCCESS) + return (result); + } + + return (ISC_R_SUCCESS); +} + +static isc_result_t +printrdata(dns_message_t *msg, dns_rdataset_t *rdataset, dns_name_t *owner, + const char *set_name, isc_boolean_t headers) +{ + isc_buffer_t target; + isc_result_t result; + isc_region_t r; + char t[4096]; + + UNUSED(msg); + if (headers) + printf(";; %s SECTION:\n", set_name); + + 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); +} + +static void +chase_cnamechain(dns_message_t *msg, dns_name_t *qname) { + isc_result_t result; + dns_rdataset_t *rdataset; + dns_rdata_cname_t cname; + dns_rdata_t rdata = DNS_RDATA_INIT; + unsigned int i = msg->counts[DNS_SECTION_ANSWER]; + + while (i-- > 0) { + rdataset = NULL; + result = dns_message_findname(msg, DNS_SECTION_ANSWER, qname, + dns_rdatatype_cname, 0, NULL, + &rdataset); + if (result != ISC_R_SUCCESS) + return; + result = dns_rdataset_first(rdataset); + check_result(result, "dns_rdataset_first"); + dns_rdata_reset(&rdata); + dns_rdataset_current(rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &cname, NULL); + check_result(result, "dns_rdata_tostruct"); + dns_name_copy(&cname.cname, qname, NULL); + dns_rdata_freestruct(&cname); + } +} + +isc_result_t +printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { + isc_boolean_t did_flag = ISC_FALSE; + dns_rdataset_t *opt, *tsig = NULL; + dns_name_t *tsigname; + isc_result_t result = ISC_R_SUCCESS; + int force_error; + + UNUSED(headers); + + /* + * We get called multiple times. + * Preserve any existing error status. + */ + force_error = (seen_error == 1) ? 1 : 0; + seen_error = 1; + if (listed_server && !printed_server) { + char sockstr[ISC_SOCKADDR_FORMATSIZE]; + + printf("Using domain server:\n"); + printf("Name: %s\n", query->userarg); + isc_sockaddr_format(&query->sockaddr, sockstr, + sizeof(sockstr)); + printf("Address: %s\n", sockstr); + printf("Aliases: \n\n"); + printed_server = ISC_TRUE; + } + + if (msg->rcode != 0) { + char namestr[DNS_NAME_FORMATSIZE]; + dns_name_format(query->lookup->name, namestr, sizeof(namestr)); + printf("Host %s not found: %d(%s)\n", + (msg->rcode != dns_rcode_nxdomain) ? namestr : + query->lookup->textname, msg->rcode, + rcode_totext(msg->rcode)); + return (ISC_R_SUCCESS); + } + + if (default_lookups && query->lookup->rdtype == dns_rdatatype_a) { + char namestr[DNS_NAME_FORMATSIZE]; + dig_lookup_t *lookup; + dns_fixedname_t fixed; + dns_name_t *name; + + /* Add AAAA and MX lookups. */ + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + dns_name_copy(query->lookup->name, name, NULL); + chase_cnamechain(msg, name); + dns_name_format(name, namestr, sizeof(namestr)); + lookup = clone_lookup(query->lookup, ISC_FALSE); + if (lookup != NULL) { + strncpy(lookup->textname, namestr, + sizeof(lookup->textname)); + lookup->textname[sizeof(lookup->textname)-1] = 0; + lookup->rdtype = dns_rdatatype_aaaa; + lookup->rdtypeset = ISC_TRUE; + lookup->origin = NULL; + lookup->retries = tries; + ISC_LIST_APPEND(lookup_list, lookup, link); + } + lookup = clone_lookup(query->lookup, ISC_FALSE); + if (lookup != NULL) { + strncpy(lookup->textname, namestr, + sizeof(lookup->textname)); + lookup->textname[sizeof(lookup->textname)-1] = 0; + lookup->rdtype = dns_rdatatype_mx; + lookup->rdtypeset = ISC_TRUE; + lookup->origin = NULL; + lookup->retries = tries; + ISC_LIST_APPEND(lookup_list, lookup, link); + } + } + + if (!short_form) { + printf(";; ->>HEADER<<- opcode: %s, status: %s, id: %u\n", + opcodetext[msg->opcode], rcode_totext(msg->rcode), + msg->id); + printf(";; flags: "); + if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) { + printf("qr"); + did_flag = ISC_TRUE; + } + if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) { + printf("%saa", did_flag ? " " : ""); + did_flag = ISC_TRUE; + } + if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) { + printf("%stc", did_flag ? " " : ""); + did_flag = ISC_TRUE; + } + if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) { + printf("%srd", did_flag ? " " : ""); + did_flag = ISC_TRUE; + } + if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) { + printf("%sra", did_flag ? " " : ""); + did_flag = ISC_TRUE; + } + if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) { + printf("%sad", did_flag ? " " : ""); + did_flag = ISC_TRUE; + } + if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) { + printf("%scd", did_flag ? " " : ""); + did_flag = ISC_TRUE; + } + printf("; QUERY: %u, ANSWER: %u, " + "AUTHORITY: %u, ADDITIONAL: %u\n", + msg->counts[DNS_SECTION_QUESTION], + msg->counts[DNS_SECTION_ANSWER], + msg->counts[DNS_SECTION_AUTHORITY], + msg->counts[DNS_SECTION_ADDITIONAL]); + opt = dns_message_getopt(msg); + if (opt != NULL) + printf(";; EDNS: version: %u, udp=%u\n", + (unsigned int)((opt->ttl & 0x00ff0000) >> 16), + (unsigned int)opt->rdclass); + tsigname = NULL; + tsig = dns_message_gettsig(msg, &tsigname); + if (tsig != NULL) + printf(";; PSEUDOSECTIONS: TSIG\n"); + } + if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_QUESTION]) && + !short_form) { + printf("\n"); + result = printsection(msg, DNS_SECTION_QUESTION, "QUESTION", + ISC_TRUE, query); + if (result != ISC_R_SUCCESS) + return (result); + } + if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) { + if (!short_form) + printf("\n"); + result = printsection(msg, DNS_SECTION_ANSWER, "ANSWER", + ISC_TF(!short_form), query); + if (result != ISC_R_SUCCESS) + return (result); + } + + if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_AUTHORITY]) && + !short_form) { + printf("\n"); + result = printsection(msg, DNS_SECTION_AUTHORITY, "AUTHORITY", + ISC_TRUE, query); + if (result != ISC_R_SUCCESS) + return (result); + } + if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ADDITIONAL]) && + !short_form) { + printf("\n"); + result = printsection(msg, DNS_SECTION_ADDITIONAL, + "ADDITIONAL", ISC_TRUE, query); + if (result != ISC_R_SUCCESS) + return (result); + } + if ((tsig != NULL) && !short_form) { + printf("\n"); + result = printrdata(msg, tsig, tsigname, + "PSEUDOSECTION TSIG", ISC_TRUE); + if (result != ISC_R_SUCCESS) + return (result); + } + if (!short_form) + printf("\n"); + + if (short_form && !default_lookups && + ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) { + char namestr[DNS_NAME_FORMATSIZE]; + char typestr[DNS_RDATATYPE_FORMATSIZE]; + dns_name_format(query->lookup->name, namestr, sizeof(namestr)); + dns_rdatatype_format(query->lookup->rdtype, typestr, + sizeof(typestr)); + printf("%s has no %s record\n", namestr, typestr); + } + seen_error = force_error; + return (result); +} + +static const char * optstring = "46ac:dilnm:rst:vwCDN:R:TW:"; + +static void +pre_parse_args(int argc, char **argv) { + int c; + + while ((c = isc_commandline_parse(argc, argv, optstring)) != -1) { + switch (c) { + case 'm': + memdebugging = ISC_TRUE; + if (strcasecmp("trace", isc_commandline_argument) == 0) + isc_mem_debugging |= ISC_MEM_DEBUGTRACE; + else if (!strcasecmp("record", + isc_commandline_argument) == 0) + isc_mem_debugging |= ISC_MEM_DEBUGRECORD; + else if (strcasecmp("usage", + isc_commandline_argument) == 0) + isc_mem_debugging |= ISC_MEM_DEBUGUSAGE; + break; + + case '4': break; + case '6': break; + case 'a': break; + case 'c': break; + case 'd': break; + case 'i': break; + case 'l': break; + case 'n': break; + case 'r': break; + case 's': break; + case 't': break; + case 'v': break; + case 'w': break; + case 'C': break; + case 'D': break; + case 'N': break; + case 'R': break; + case 'T': break; + case 'W': break; + default: + show_usage(); + } + } + isc_commandline_reset = ISC_TRUE; + isc_commandline_index = 1; +} + +static void +parse_args(isc_boolean_t is_batchfile, int argc, char **argv) { + char hostname[MXNAME]; + dig_lookup_t *lookup; + int c; + char store[MXNAME]; + isc_textregion_t tr; + isc_result_t result = ISC_R_SUCCESS; + dns_rdatatype_t rdtype; + dns_rdataclass_t rdclass; + isc_uint32_t serial = 0; + + UNUSED(is_batchfile); + + lookup = make_empty_lookup(); + + lookup->servfail_stops = ISC_FALSE; + lookup->comments = ISC_FALSE; + + while ((c = isc_commandline_parse(argc, argv, optstring)) != -1) { + switch (c) { + case 'l': + lookup->tcp_mode = ISC_TRUE; + lookup->rdtype = dns_rdatatype_axfr; + lookup->rdtypeset = ISC_TRUE; + fatalexit = 3; + break; + case 'v': + case 'd': + short_form = ISC_FALSE; + break; + case 'r': + lookup->recurse = ISC_FALSE; + break; + case 't': + if (strncasecmp(isc_commandline_argument, + "ixfr=", 5) == 0) { + rdtype = dns_rdatatype_ixfr; + /* XXXMPA add error checking */ + serial = strtoul(isc_commandline_argument + 5, + NULL, 10); + result = ISC_R_SUCCESS; + } else { + tr.base = isc_commandline_argument; + tr.length = strlen(isc_commandline_argument); + result = dns_rdatatype_fromtext(&rdtype, + (isc_textregion_t *)&tr); + } + + if (result != ISC_R_SUCCESS) { + fatalexit = 2; + fatal("invalid type: %s\n", + isc_commandline_argument); + } + if (!lookup->rdtypeset || + lookup->rdtype != dns_rdatatype_axfr) + lookup->rdtype = rdtype; + lookup->rdtypeset = ISC_TRUE; +#ifdef WITH_IDN + idnoptions = 0; +#endif + if (rdtype == dns_rdatatype_axfr) { + /* -l -t any -v */ + list_type = dns_rdatatype_any; + short_form = ISC_FALSE; + lookup->tcp_mode = ISC_TRUE; + } else if (rdtype == dns_rdatatype_ixfr) { + lookup->ixfr_serial = serial; + lookup->tcp_mode = ISC_TRUE; + list_type = rdtype; +#ifdef WITH_IDN + } else if (rdtype == dns_rdatatype_a || + rdtype == dns_rdatatype_aaaa || + rdtype == dns_rdatatype_mx) { + idnoptions = IDN_ASCCHECK; + list_type = rdtype; +#endif + } else + list_type = rdtype; + list_addresses = ISC_FALSE; + default_lookups = ISC_FALSE; + break; + case 'c': + tr.base = isc_commandline_argument; + tr.length = strlen(isc_commandline_argument); + result = dns_rdataclass_fromtext(&rdclass, + (isc_textregion_t *)&tr); + + if (result != ISC_R_SUCCESS) { + fatalexit = 2; + fatal("invalid class: %s\n", + isc_commandline_argument); + } else { + lookup->rdclass = rdclass; + lookup->rdclassset = ISC_TRUE; + } + default_lookups = ISC_FALSE; + break; + case 'a': + if (!lookup->rdtypeset || + lookup->rdtype != dns_rdatatype_axfr) + lookup->rdtype = dns_rdatatype_any; + list_type = dns_rdatatype_any; + list_addresses = ISC_FALSE; + lookup->rdtypeset = ISC_TRUE; + short_form = ISC_FALSE; + default_lookups = ISC_FALSE; + break; + case 'i': + lookup->ip6_int = ISC_TRUE; + break; + case 'n': + /* deprecated */ + break; + case 'm': + /* Handled by pre_parse_args(). */ + break; + case 'w': + /* + * The timer routines are coded such that + * timeout==MAXINT doesn't enable the timer + */ + timeout = INT_MAX; + break; + case 'W': + timeout = atoi(isc_commandline_argument); + if (timeout < 1) + timeout = 1; + break; + case 'R': + tries = atoi(isc_commandline_argument) + 1; + if (tries < 2) + tries = 2; + break; + case 'T': + lookup->tcp_mode = ISC_TRUE; + break; + case 'C': + debug("showing all SOAs"); + lookup->rdtype = dns_rdatatype_ns; + lookup->rdtypeset = ISC_TRUE; + lookup->rdclass = dns_rdataclass_in; + lookup->rdclassset = ISC_TRUE; + lookup->ns_search_only = ISC_TRUE; + lookup->trace_root = ISC_TRUE; + lookup->identify_previous_line = ISC_TRUE; + default_lookups = ISC_FALSE; + break; + case 'N': + debug("setting NDOTS to %s", + isc_commandline_argument); + ndots = atoi(isc_commandline_argument); + break; + case 'D': + debugging = ISC_TRUE; + break; + case '4': + if (have_ipv4) { + isc_net_disableipv6(); + have_ipv6 = ISC_FALSE; + } else + fatal("can't find IPv4 networking"); + break; + case '6': + if (have_ipv6) { + isc_net_disableipv4(); + have_ipv4 = ISC_FALSE; + } else + fatal("can't find IPv6 networking"); + break; + case 's': + lookup->servfail_stops = ISC_TRUE; + break; + } + } + + lookup->retries = tries; + + if (isc_commandline_index >= argc) + show_usage(); + + strncpy(hostname, argv[isc_commandline_index], sizeof(hostname)); + hostname[sizeof(hostname)-1]=0; + if (argc > isc_commandline_index + 1) { + set_nameserver(argv[isc_commandline_index+1]); + debug("server is %s", argv[isc_commandline_index+1]); + listed_server = ISC_TRUE; + } else + check_ra = ISC_TRUE; + + lookup->pending = ISC_FALSE; + if (get_reverse(store, sizeof(store), hostname, + lookup->ip6_int, ISC_TRUE) == ISC_R_SUCCESS) { + strncpy(lookup->textname, store, sizeof(lookup->textname)); + lookup->textname[sizeof(lookup->textname)-1] = 0; + lookup->rdtype = dns_rdatatype_ptr; + lookup->rdtypeset = ISC_TRUE; + default_lookups = ISC_FALSE; + } else { + strncpy(lookup->textname, hostname, sizeof(lookup->textname)); + lookup->textname[sizeof(lookup->textname)-1]=0; + usesearch = ISC_TRUE; + } + lookup->new_search = ISC_TRUE; + ISC_LIST_APPEND(lookup_list, lookup, link); +} + +int +main(int argc, char **argv) { + isc_result_t result; + + tries = 2; + + ISC_LIST_INIT(lookup_list); + ISC_LIST_INIT(server_list); + ISC_LIST_INIT(search_list); + + fatalexit = 1; +#ifdef WITH_IDN + idnoptions = IDN_ASCCHECK; +#endif + + debug("main()"); + progname = argv[0]; + pre_parse_args(argc, argv); + result = isc_app_start(); + check_result(result, "isc_app_start"); + setup_libs(); + parse_args(ISC_FALSE, argc, argv); + setup_system(); + result = isc_app_onrun(mctx, global_task, onrun_callback, NULL); + check_result(result, "isc_app_onrun"); + isc_app_run(); + cancel_all(); + destroy_libs(); + isc_app_finish(); + return ((seen_error == 0) ? 0 : 1); +} diff --git a/contrib/bind-9.5.2/bin/dig/host.html b/contrib/bind-9.5.2/bin/dig/host.html new file mode 100644 index 0000000000..de1323e23c --- /dev/null +++ b/contrib/bind-9.5.2/bin/dig/host.html @@ -0,0 +1,212 @@ + + + + + +host + + +
+
+
+

Name

+

host — DNS lookup utility

+
+
+

Synopsis

+

host [-aCdlnrsTwv] [-c class] [-N ndots] [-R number] [-t type] [-W wait] [-m flag] [-4] [-6] {name} [server]

+
+
+

DESCRIPTION

+

host + is a simple utility for performing DNS lookups. + It is normally used to convert names to IP addresses and vice versa. + When no arguments or options are given, + host + prints a short summary of its command line arguments and options. +

+

name is the domain name that is to be + looked + up. It can also be a dotted-decimal IPv4 address or a colon-delimited + IPv6 address, in which case host will by + default + perform a reverse lookup for that address. + server is an optional argument which + is either + the name or IP address of the name server that host + should query instead of the server or servers listed in + /etc/resolv.conf. +

+

+ The -a (all) option is equivalent to setting the + -v option and asking host to make + a query of type ANY. +

+

+ When the -C option is used, host + will attempt to display the SOA records for zone + name from all the listed + authoritative name + servers for that zone. The list of name servers is defined by the NS + records that are found for the zone. +

+

+ The -c option instructs to make a DNS query of class + class. This can be used to lookup + Hesiod or + Chaosnet class resource records. The default class is IN (Internet). +

+

+ Verbose output is generated by host when + the + -d or -v option is used. The two + options are equivalent. They have been provided for backwards + compatibility. In previous versions, the -d option + switched on debugging traces and -v enabled verbose + output. +

+

+ List mode is selected by the -l option. This makes + host perform a zone transfer for zone + name. Transfer the zone printing out + the NS, PTR + and address records (A/AAAA). If combined with -a + all records will be printed. +

+

+ The -i + option specifies that reverse lookups of IPv6 addresses should + use the IP6.INT domain as defined in RFC1886. + The default is to use IP6.ARPA. +

+

+ The -N option sets the number of dots that have to be + in name for it to be considered + absolute. The + default value is that defined using the ndots statement in + /etc/resolv.conf, or 1 if no ndots + statement is + present. Names with fewer dots are interpreted as relative names and + will be searched for in the domains listed in the search + or domain directive in + /etc/resolv.conf. +

+

+ The number of UDP retries for a lookup can be changed with the + -R option. number + indicates + how many times host will repeat a query + that does + not get answered. The default number of retries is 1. If + number is negative or zero, the + number of + retries will default to 1. +

+

+ Non-recursive queries can be made via the -r option. + Setting this option clears the RD — recursion + desired — bit in the query which host makes. + This should mean that the name server receiving the query will not + attempt to resolve name. The + -r option enables host + to mimic + the behavior of a name server by making non-recursive queries and + expecting to receive answers to those queries that are usually + referrals to other name servers. +

+

+ By default, host uses UDP when making + queries. The + -T option makes it use a TCP connection when querying + the name server. TCP will be automatically selected for queries that + require it, such as zone transfer (AXFR) requests. +

+

+ The -4 option forces host to only + use IPv4 query transport. The -6 option forces + host to only use IPv6 query transport. +

+

+ The -t option is used to select the query type. + type can be any recognized query + type: CNAME, + NS, SOA, SIG, KEY, AXFR, etc. When no query type is specified, + host automatically selects an appropriate + query + type. By default, it looks for A, AAAA, and MX records, but if the + -C option was given, queries will be made for SOA + records, and if name is a + dotted-decimal IPv4 + address or colon-delimited IPv6 address, host will + query for PTR records. If a query type of IXFR is chosen the starting + serial number can be specified by appending an equal followed by the + starting serial number (e.g. -t IXFR=12345678). +

+

+ The time to wait for a reply can be controlled through the + -W and -w options. The + -W option makes host + wait for + wait seconds. If wait + is less than one, the wait interval is set to one second. When the + -w option is used, host + will + effectively wait forever for a reply. The time to wait for a response + will be set to the number of seconds given by the hardware's maximum + value for an integer quantity. +

+

+ The -s option tells host + not to send the query to the next nameserver + if any server responds with a SERVFAIL response, which is the + reverse of normal stub resolver behavior. +

+

+ The -m can be used to set the memory usage debugging + flags + record, usage and + trace. +

+
+
+

IDN SUPPORT

+

+ If host has been built with IDN (internationalized + domain name) support, it can accept and display non-ASCII domain names. + host appropriately converts character encoding of + domain name before sending a request to DNS server or displaying a + reply from the server. + If you'd like to turn off the IDN support for some reason, defines + the IDN_DISABLE environment variable. + The IDN support is disabled if the variable is set when + host runs. +

+
+
+

FILES

+

/etc/resolv.conf +

+
+
+

SEE ALSO

+

dig(1), + named(8). +

+
+
+ diff --git a/contrib/bind-9.5.2/bin/dig/include/dig/dig.h b/contrib/bind-9.5.2/bin/dig/include/dig/dig.h new file mode 100644 index 0000000000..bfb3acb37c --- /dev/null +++ b/contrib/bind-9.5.2/bin/dig/include/dig/dig.h @@ -0,0 +1,406 @@ +/* + * 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 + * 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: dig.h,v 1.105.130.3 2008/12/16 02:59:46 jinmei Exp $ */ + +#ifndef DIG_H +#define DIG_H + +/*! \file */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MXSERV 20 +#define MXNAME (DNS_NAME_MAXTEXT+1) +#define MXRD 32 +/*% Buffer Size */ +#define BUFSIZE 512 +#define COMMSIZE 0xffff +#ifndef RESOLV_CONF +/*% location of resolve.conf */ +#define RESOLV_CONF "/etc/resolv.conf" +#endif +/*% output buffer */ +#define OUTPUTBUF 32767 +/*% Max RR Limit */ +#define MAXRRLIMIT 0xffffffff +#define MAXTIMEOUT 0xffff +/*% Max number of tries */ +#define MAXTRIES 0xffffffff +/*% Max number of dots */ +#define MAXNDOTS 0xffff +/*% Max number of ports */ +#define MAXPORT 0xffff +/*% Max serial number */ +#define MAXSERIAL 0xffffffff + +/*% Default TCP Timeout */ +#define TCP_TIMEOUT 10 +/*% Default UDP Timeout */ +#define UDP_TIMEOUT 5 + +#define SERVER_TIMEOUT 1 + +#define LOOKUP_LIMIT 64 +/*% + * Lookup_limit is just a limiter, keeping too many lookups from being + * created. It's job is mainly to prevent the program from running away + * in a tight loop of constant lookups. It's value is arbitrary. + */ + +/* + * Defaults for the sigchase suboptions. Consolidated here because + * these control the layout of dig_lookup_t (among other things). + */ +#ifdef DIG_SIGCHASE +#ifndef DIG_SIGCHASE_BU +#define DIG_SIGCHASE_BU 1 +#endif +#ifndef DIG_SIGCHASE_TD +#define DIG_SIGCHASE_TD 1 +#endif +#endif + +ISC_LANG_BEGINDECLS + +typedef struct dig_lookup dig_lookup_t; +typedef struct dig_query dig_query_t; +typedef struct dig_server dig_server_t; +#ifdef DIG_SIGCHASE +typedef struct dig_message dig_message_t; +#endif +typedef ISC_LIST(dig_server_t) dig_serverlist_t; +typedef struct dig_searchlist dig_searchlist_t; + +/*% The dig_lookup structure */ +struct dig_lookup { + isc_boolean_t + pending, /*%< Pending a successful answer */ + waiting_connect, + doing_xfr, + ns_search_only, /*%< dig +nssearch, host -C */ + identify, /*%< Append an "on server " message */ + identify_previous_line, /*% Prepend a "Nameserver :" + message, with newline and tab */ + ignore, + recurse, + aaonly, + adflag, + cdflag, + trace, /*% dig +trace */ + trace_root, /*% initial query for either +trace or +nssearch */ + tcp_mode, + ip6_int, + comments, + stats, + section_question, + section_answer, + section_authority, + section_additional, + servfail_stops, + new_search, + need_search, + done_as_is, + besteffort, + dnssec, + nsid; /*% Name Server ID (RFC 5001) */ +#ifdef DIG_SIGCHASE +isc_boolean_t sigchase; +#if DIG_SIGCHASE_TD + isc_boolean_t do_topdown, + trace_root_sigchase, + rdtype_sigchaseset, + rdclass_sigchaseset; + /* Name we are going to validate RRset */ + char textnamesigchase[MXNAME]; +#endif +#endif + + char textname[MXNAME]; /*% Name we're going to be looking up */ + char cmdline[MXNAME]; + dns_rdatatype_t rdtype; + dns_rdatatype_t qrdtype; +#if DIG_SIGCHASE_TD + dns_rdatatype_t rdtype_sigchase; + dns_rdatatype_t qrdtype_sigchase; + dns_rdataclass_t rdclass_sigchase; +#endif + dns_rdataclass_t rdclass; + isc_boolean_t rdtypeset; + isc_boolean_t rdclassset; + char namespace[BUFSIZE]; + char onamespace[BUFSIZE]; + isc_buffer_t namebuf; + isc_buffer_t onamebuf; + isc_buffer_t renderbuf; + char *sendspace; + dns_name_t *name; + isc_timer_t *timer; + isc_interval_t interval; + dns_message_t *sendmsg; + dns_name_t *oname; + ISC_LINK(dig_lookup_t) link; + ISC_LIST(dig_query_t) q; + dig_query_t *current_query; + dig_serverlist_t my_server_list; + dig_searchlist_t *origin; + dig_query_t *xfr_q; + isc_uint32_t retries; + int nsfound; + isc_uint16_t udpsize; + isc_int16_t edns; + isc_uint32_t ixfr_serial; + isc_buffer_t rdatabuf; + char rdatastore[MXNAME]; + dst_context_t *tsigctx; + isc_buffer_t *querysig; + isc_uint32_t msgcounter; + dns_fixedname_t fdomain; +}; + +/*% The dig_query structure */ +struct dig_query { + dig_lookup_t *lookup; + isc_boolean_t waiting_connect, + pending_free, + waiting_senddone, + first_pass, + first_soa_rcvd, + second_rr_rcvd, + first_repeat_rcvd, + recv_made, + warn_id; + isc_uint32_t first_rr_serial; + isc_uint32_t second_rr_serial; + isc_uint32_t msg_count; + isc_uint32_t rr_count; + char *servname; + char *userarg; + isc_bufferlist_t sendlist, + recvlist, + lengthlist; + isc_buffer_t recvbuf, + lengthbuf, + slbuf; + char *recvspace, + lengthspace[4], + slspace[4]; + isc_socket_t *sock; + ISC_LINK(dig_query_t) link; + isc_sockaddr_t sockaddr; + isc_time_t time_sent; + isc_uint64_t byte_count; + isc_buffer_t sendbuf; +}; + +struct dig_server { + char servername[MXNAME]; + char userarg[MXNAME]; + ISC_LINK(dig_server_t) link; +}; + +struct dig_searchlist { + char origin[MXNAME]; + ISC_LINK(dig_searchlist_t) link; +}; +#ifdef DIG_SIGCHASE +struct dig_message { + dns_message_t *msg; + ISC_LINK(dig_message_t) link; +}; +#endif + +typedef ISC_LIST(dig_searchlist_t) dig_searchlistlist_t; +typedef ISC_LIST(dig_lookup_t) dig_lookuplist_t; + +/* + * Externals from dighost.c + */ + +extern dig_lookuplist_t lookup_list; +extern dig_serverlist_t server_list; +extern dig_searchlistlist_t search_list; +extern unsigned int extrabytes; + +extern isc_boolean_t check_ra, have_ipv4, have_ipv6, specified_source, + usesearch, showsearch, qr; +extern in_port_t port; +extern unsigned int timeout; +extern isc_mem_t *mctx; +extern dns_messageid_t id; +extern int sendcount; +extern int ndots; +extern int lookup_counter; +extern int exitcode; +extern isc_sockaddr_t bind_address; +extern char keynametext[MXNAME]; +extern char keyfile[MXNAME]; +extern char keysecret[MXNAME]; +extern dns_name_t *hmacname; +extern unsigned int digestbits; +#ifdef DIG_SIGCHASE +extern char trustedkey[MXNAME]; +#endif +extern dns_tsigkey_t *key; +extern isc_boolean_t validated; +extern isc_taskmgr_t *taskmgr; +extern isc_task_t *global_task; +extern isc_boolean_t free_now; +extern isc_boolean_t debugging, memdebugging; + +extern char *progname; +extern int tries; +extern int fatalexit; +#ifdef WITH_IDN +extern int idnoptions; +#endif + +/* + * Routines in dighost.c. + */ +isc_result_t +get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr); + +isc_result_t +get_reverse(char *reverse, size_t len, char *value, isc_boolean_t ip6_int, + isc_boolean_t strict); + +void +fatal(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +void +debug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +void +check_result(isc_result_t result, const char *msg); + +void +setup_lookup(dig_lookup_t *lookup); + +void +destroy_lookup(dig_lookup_t *lookup); + +void +do_lookup(dig_lookup_t *lookup); + +void +start_lookup(void); + +void +onrun_callback(isc_task_t *task, isc_event_t *event); + +int +dhmain(int argc, char **argv); + +void +setup_libs(void); + +void +setup_system(void); + +dig_lookup_t * +requeue_lookup(dig_lookup_t *lookold, isc_boolean_t servers); + +dig_lookup_t * +make_empty_lookup(void); + +dig_lookup_t * +clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers); + +dig_server_t * +make_server(const char *servname, const char *userarg); + +void +flush_server_list(void); + +void +set_nameserver(char *opt); + +void +clone_server_list(dig_serverlist_t src, + dig_serverlist_t *dest); + +void +cancel_all(void); + +void +destroy_libs(void); + +void +set_search_domain(char *domain); + +#ifdef DIG_SIGCHASE +void +clean_trustedkey(void); +#endif + +/* + * Routines to be defined in dig.c, host.c, and nslookup.c. + */ +#ifdef DIG_SIGCHASE +isc_result_t +printrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset, + isc_buffer_t *target); +#endif + +isc_result_t +printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers); +/*%< + * Print the final result of the lookup. + */ + +void +received(int bytes, isc_sockaddr_t *from, dig_query_t *query); +/*%< + * Print a message about where and when the response + * was received from, like the final comment in the + * output of "dig". + */ + +void +trying(char *frm, dig_lookup_t *lookup); + +void +dighost_shutdown(void); + +char * +next_token(char **stringp, const char *delim); + +#ifdef DIG_SIGCHASE +/* Chasing functions */ +dns_rdataset_t * +chase_scanname(dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers); +void +chase_sig(dns_message_t *msg); +#endif + +ISC_LANG_ENDDECLS + +#endif diff --git a/contrib/bind-9.5.2/bin/dig/nslookup.1 b/contrib/bind-9.5.2/bin/dig/nslookup.1 new file mode 100644 index 0000000000..4fde34c0fc --- /dev/null +++ b/contrib/bind-9.5.2/bin/dig/nslookup.1 @@ -0,0 +1,252 @@ +.\" Copyright (C) 2004-2007 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: nslookup.1,v 1.14.150.1 2009/07/11 01:43:27 tbox Exp $ +.\" +.hy 0 +.ad l +.\" Title: nslookup +.\" Author: +.\" Generator: DocBook XSL Stylesheets v1.71.1 +.\" Date: Jun 30, 2000 +.\" Manual: BIND9 +.\" Source: BIND9 +.\" +.TH "NSLOOKUP" "1" "Jun 30, 2000" "BIND9" "BIND9" +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.SH "NAME" +nslookup \- query Internet name servers interactively +.SH "SYNOPSIS" +.HP 9 +\fBnslookup\fR [\fB\-option\fR] [name\ |\ \-] [server] +.SH "DESCRIPTION" +.PP +\fBNslookup\fR +is a program to query Internet domain name servers. +\fBNslookup\fR +has two modes: interactive and non\-interactive. Interactive mode allows the user to query name servers for information about various hosts and domains or to print a list of hosts in a domain. Non\-interactive mode is used to print just the name and requested information for a host or domain. +.SH "ARGUMENTS" +.PP +Interactive mode is entered in the following cases: +.TP 4 +1. +when no arguments are given (the default name server will be used) +.TP 4 +2. +when the first argument is a hyphen (\-) and the second argument is the host name or Internet address of a name server. +.sp +.RE +.PP +Non\-interactive mode is used when the name or Internet address of the host to be looked up is given as the first argument. The optional second argument specifies the host name or address of a name server. +.PP +Options can also be specified on the command line if they precede the arguments and are prefixed with a hyphen. For example, to change the default query type to host information, and the initial timeout to 10 seconds, type: +.sp .RS 4 .nf nslookup \-query=hinfo \-timeout=10 .fi .RE +.SH "INTERACTIVE COMMANDS" +.PP +\fBhost\fR [server] +.RS 4 +Look up information for host using the current default server or using server, if specified. If host is an Internet address and the query type is A or PTR, the name of the host is returned. If host is a name and does not have a trailing period, the search list is used to qualify the name. +.sp +To look up a host not in the current domain, append a period to the name. +.RE +.PP +\fBserver\fR \fIdomain\fR +.RS 4 +.RE +.PP +\fBlserver\fR \fIdomain\fR +.RS 4 +Change the default server to +\fIdomain\fR; +\fBlserver\fR +uses the initial server to look up information about +\fIdomain\fR, while +\fBserver\fR +uses the current default server. If an authoritative answer can't be found, the names of servers that might have the answer are returned. +.RE +.PP +\fBroot\fR +.RS 4 +not implemented +.RE +.PP +\fBfinger\fR +.RS 4 +not implemented +.RE +.PP +\fBls\fR +.RS 4 +not implemented +.RE +.PP +\fBview\fR +.RS 4 +not implemented +.RE +.PP +\fBhelp\fR +.RS 4 +not implemented +.RE +.PP +\fB?\fR +.RS 4 +not implemented +.RE +.PP +\fBexit\fR +.RS 4 +Exits the program. +.RE +.PP +\fBset\fR \fIkeyword\fR\fI[=value]\fR +.RS 4 +This command is used to change state information that affects the lookups. Valid keywords are: +.RS 4 +.PP +\fBall\fR +.RS 4 +Prints the current values of the frequently used options to +\fBset\fR. Information about the current default server and host is also printed. +.RE +.PP +\fBclass=\fR\fIvalue\fR +.RS 4 +Change the query class to one of: +.RS 4 +.PP +\fBIN\fR +.RS 4 +the Internet class +.RE +.PP +\fBCH\fR +.RS 4 +the Chaos class +.RE +.PP +\fBHS\fR +.RS 4 +the Hesiod class +.RE +.PP +\fBANY\fR +.RS 4 +wildcard +.RE +.RE +.IP "" 4 +The class specifies the protocol group of the information. +.sp +(Default = IN; abbreviation = cl) +.RE +.PP +\fB \fR\fB\fI[no]\fR\fR\fBdebug\fR +.RS 4 +Turn on or off the display of the full response packet and any intermediate response packets when searching. +.sp +(Default = nodebug; abbreviation = +[no]deb) +.RE +.PP +\fB \fR\fB\fI[no]\fR\fR\fBd2\fR +.RS 4 +Turn debugging mode on or off. This displays more about what nslookup is doing. +.sp +(Default = nod2) +.RE +.PP +\fBdomain=\fR\fIname\fR +.RS 4 +Sets the search list to +\fIname\fR. +.RE +.PP +\fB \fR\fB\fI[no]\fR\fR\fBsearch\fR +.RS 4 +If the lookup request contains at least one period but doesn't end with a trailing period, append the domain names in the domain search list to the request until an answer is received. +.sp +(Default = search) +.RE +.PP +\fBport=\fR\fIvalue\fR +.RS 4 +Change the default TCP/UDP name server port to +\fIvalue\fR. +.sp +(Default = 53; abbreviation = po) +.RE +.PP +\fBquerytype=\fR\fIvalue\fR +.RS 4 +.RE +.PP +\fBtype=\fR\fIvalue\fR +.RS 4 +Change the type of the information query. +.sp +(Default = A; abbreviations = q, ty) +.RE +.PP +\fB \fR\fB\fI[no]\fR\fR\fBrecurse\fR +.RS 4 +Tell the name server to query other servers if it does not have the information. +.sp +(Default = recurse; abbreviation = [no]rec) +.RE +.PP +\fBretry=\fR\fInumber\fR +.RS 4 +Set the number of retries to number. +.RE +.PP +\fBtimeout=\fR\fInumber\fR +.RS 4 +Change the initial timeout interval for waiting for a reply to number seconds. +.RE +.PP +\fB \fR\fB\fI[no]\fR\fR\fBvc\fR +.RS 4 +Always use a virtual circuit when sending requests to the server. +.sp +(Default = novc) +.RE +.PP +\fB \fR\fB\fI[no]\fR\fR\fBfail\fR +.RS 4 +Try the next nameserver if a nameserver responds with SERVFAIL or a referral (nofail) or terminate query (fail) on such a response. +.sp +(Default = nofail) +.RE +.RE +.IP "" 4 +.RE +.SH "FILES" +.PP +\fI/etc/resolv.conf\fR +.SH "SEE ALSO" +.PP +\fBdig\fR(1), +\fBhost\fR(1), +\fBnamed\fR(8). +.SH "AUTHOR" +.PP +Andrew Cherenson +.SH "COPYRIGHT" +Copyright \(co 2004\-2007 Internet Systems Consortium, Inc. ("ISC") +.br diff --git a/contrib/bind-9.5.2/bin/dig/nslookup.c b/contrib/bind-9.5.2/bin/dig/nslookup.c new file mode 100644 index 0000000000..bba97d6934 --- /dev/null +++ b/contrib/bind-9.5.2/bin/dig/nslookup.c @@ -0,0 +1,912 @@ +/* + * 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 + * 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: nslookup.c,v 1.117.130.5 2009/05/06 23:46:49 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 + +static isc_boolean_t short_form = ISC_TRUE, + tcpmode = ISC_FALSE, + identify = ISC_FALSE, stats = ISC_TRUE, + comments = ISC_TRUE, section_question = ISC_TRUE, + section_answer = ISC_TRUE, section_authority = ISC_TRUE, + section_additional = ISC_TRUE, recurse = ISC_TRUE, + aaonly = ISC_FALSE, nofail = ISC_TRUE; + +static isc_boolean_t in_use = ISC_FALSE; +static char defclass[MXRD] = "IN"; +static char deftype[MXRD] = "A"; +static isc_event_t *global_event = NULL; + +static char domainopt[DNS_NAME_MAXTEXT]; + +static const char *rcodetext[] = { + "NOERROR", + "FORMERR", + "SERVFAIL", + "NXDOMAIN", + "NOTIMP", + "REFUSED", + "YXDOMAIN", + "YXRRSET", + "NXRRSET", + "NOTAUTH", + "NOTZONE", + "RESERVED11", + "RESERVED12", + "RESERVED13", + "RESERVED14", + "RESERVED15", + "BADVERS" +}; + +static const char *rtypetext[] = { + "rtype_0 = ", /* 0 */ + "internet address = ", /* 1 */ + "nameserver = ", /* 2 */ + "md = ", /* 3 */ + "mf = ", /* 4 */ + "canonical name = ", /* 5 */ + "soa = ", /* 6 */ + "mb = ", /* 7 */ + "mg = ", /* 8 */ + "mr = ", /* 9 */ + "rtype_10 = ", /* 10 */ + "protocol = ", /* 11 */ + "name = ", /* 12 */ + "hinfo = ", /* 13 */ + "minfo = ", /* 14 */ + "mail exchanger = ", /* 15 */ + "text = ", /* 16 */ + "rp = ", /* 17 */ + "afsdb = ", /* 18 */ + "x25 address = ", /* 19 */ + "isdn address = ", /* 20 */ + "rt = ", /* 21 */ + "nsap = ", /* 22 */ + "nsap_ptr = ", /* 23 */ + "signature = ", /* 24 */ + "key = ", /* 25 */ + "px = ", /* 26 */ + "gpos = ", /* 27 */ + "has AAAA address ", /* 28 */ + "loc = ", /* 29 */ + "next = ", /* 30 */ + "rtype_31 = ", /* 31 */ + "rtype_32 = ", /* 32 */ + "service = ", /* 33 */ + "rtype_34 = ", /* 34 */ + "naptr = ", /* 35 */ + "kx = ", /* 36 */ + "cert = ", /* 37 */ + "v6 address = ", /* 38 */ + "dname = ", /* 39 */ + "rtype_40 = ", /* 40 */ + "optional = " /* 41 */ +}; + +#define N_KNOWN_RRTYPES (sizeof(rtypetext) / sizeof(rtypetext[0])) + +static void flush_lookup_list(void); +static void getinput(isc_task_t *task, isc_event_t *event); + +static char * +rcode_totext(dns_rcode_t rcode) +{ + static char buf[sizeof("?65535")]; + union { + const char *consttext; + char *deconsttext; + } totext; + + if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) { + snprintf(buf, sizeof(buf), "?%u", rcode); + totext.deconsttext = buf; + } else + totext.consttext = rcodetext[rcode]; + return totext.deconsttext; +} + +void +dighost_shutdown(void) { + isc_event_t *event = global_event; + + flush_lookup_list(); + debug("dighost_shutdown()"); + + if (!in_use) { + isc_app_shutdown(); + return; + } + + isc_task_send(global_task, &event); +} + +static void +printsoa(dns_rdata_t *rdata) { + dns_rdata_soa_t soa; + isc_result_t result; + char namebuf[DNS_NAME_FORMATSIZE]; + + result = dns_rdata_tostruct(rdata, &soa, NULL); + check_result(result, "dns_rdata_tostruct"); + + dns_name_format(&soa.origin, namebuf, sizeof(namebuf)); + printf("\torigin = %s\n", namebuf); + dns_name_format(&soa.contact, namebuf, sizeof(namebuf)); + printf("\tmail addr = %s\n", namebuf); + printf("\tserial = %u\n", soa.serial); + printf("\trefresh = %u\n", soa.refresh); + printf("\tretry = %u\n", soa.retry); + printf("\texpire = %u\n", soa.expire); + printf("\tminimum = %u\n", soa.minimum); + dns_rdata_freestruct(&soa); +} + +static void +printa(dns_rdata_t *rdata) { + isc_result_t result; + char text[sizeof("255.255.255.255")]; + isc_buffer_t b; + + isc_buffer_init(&b, text, sizeof(text)); + result = dns_rdata_totext(rdata, NULL, &b); + check_result(result, "dns_rdata_totext"); + printf("Address: %.*s\n", (int)isc_buffer_usedlength(&b), + (char *)isc_buffer_base(&b)); +} +#ifdef DIG_SIGCHASE +/* Just for compatibility : not use in host program */ +isc_result_t +printrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset, + isc_buffer_t *target) +{ + UNUSED(owner_name); + UNUSED(rdataset); + UNUSED(target); + return(ISC_FALSE); +} +#endif +static void +printrdata(dns_rdata_t *rdata) { + isc_result_t result; + isc_buffer_t *b = NULL; + unsigned int size = 1024; + isc_boolean_t done = ISC_FALSE; + + if (rdata->type < N_KNOWN_RRTYPES) + printf("%s", rtypetext[rdata->type]); + else + printf("rdata_%d = ", rdata->type); + + while (!done) { + result = isc_buffer_allocate(mctx, &b, size); + if (result != ISC_R_SUCCESS) + check_result(result, "isc_buffer_allocate"); + result = dns_rdata_totext(rdata, NULL, b); + if (result == ISC_R_SUCCESS) { + printf("%.*s\n", (int)isc_buffer_usedlength(b), + (char *)isc_buffer_base(b)); + done = ISC_TRUE; + } else if (result != ISC_R_NOSPACE) + check_result(result, "dns_rdata_totext"); + isc_buffer_free(&b); + size *= 2; + } +} + +static isc_result_t +printsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, + dns_section_t section) { + isc_result_t result, loopresult; + dns_name_t *name; + dns_rdataset_t *rdataset = NULL; + dns_rdata_t rdata = DNS_RDATA_INIT; + char namebuf[DNS_NAME_FORMATSIZE]; + + UNUSED(query); + UNUSED(headers); + + debug("printsection()"); + + result = dns_message_firstname(msg, section); + if (result == ISC_R_NOMORE) + return (ISC_R_SUCCESS); + else if (result != ISC_R_SUCCESS) + return (result); + for (;;) { + name = NULL; + dns_message_currentname(msg, section, + &name); + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) { + loopresult = dns_rdataset_first(rdataset); + while (loopresult == ISC_R_SUCCESS) { + dns_rdataset_current(rdataset, &rdata); + switch (rdata.type) { + case dns_rdatatype_a: + if (section != DNS_SECTION_ANSWER) + goto def_short_section; + dns_name_format(name, namebuf, + sizeof(namebuf)); + printf("Name:\t%s\n", namebuf); + printa(&rdata); + break; + case dns_rdatatype_soa: + dns_name_format(name, namebuf, + sizeof(namebuf)); + printf("%s\n", namebuf); + printsoa(&rdata); + break; + default: + def_short_section: + dns_name_format(name, namebuf, + sizeof(namebuf)); + printf("%s\t", namebuf); + printrdata(&rdata); + break; + } + dns_rdata_reset(&rdata); + loopresult = dns_rdataset_next(rdataset); + } + } + result = dns_message_nextname(msg, section); + if (result == ISC_R_NOMORE) + break; + else if (result != ISC_R_SUCCESS) { + return (result); + } + } + return (ISC_R_SUCCESS); +} + +static isc_result_t +detailsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, + dns_section_t section) { + isc_result_t result, loopresult; + dns_name_t *name; + dns_rdataset_t *rdataset = NULL; + dns_rdata_t rdata = DNS_RDATA_INIT; + char namebuf[DNS_NAME_FORMATSIZE]; + + UNUSED(query); + + debug("detailsection()"); + + if (headers) { + switch (section) { + case DNS_SECTION_QUESTION: + puts(" QUESTIONS:"); + break; + case DNS_SECTION_ANSWER: + puts(" ANSWERS:"); + break; + case DNS_SECTION_AUTHORITY: + puts(" AUTHORITY RECORDS:"); + break; + case DNS_SECTION_ADDITIONAL: + puts(" ADDITIONAL RECORDS:"); + break; + } + } + + result = dns_message_firstname(msg, section); + if (result == ISC_R_NOMORE) + return (ISC_R_SUCCESS); + else if (result != ISC_R_SUCCESS) + return (result); + for (;;) { + name = NULL; + dns_message_currentname(msg, section, + &name); + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) { + if (section == DNS_SECTION_QUESTION) { + dns_name_format(name, namebuf, + sizeof(namebuf)); + printf("\t%s, ", namebuf); + dns_rdatatype_format(rdataset->type, + namebuf, + sizeof(namebuf)); + printf("type = %s, ", namebuf); + dns_rdataclass_format(rdataset->rdclass, + namebuf, + sizeof(namebuf)); + printf("class = %s\n", namebuf); + } + loopresult = dns_rdataset_first(rdataset); + while (loopresult == ISC_R_SUCCESS) { + dns_rdataset_current(rdataset, &rdata); + + dns_name_format(name, namebuf, + sizeof(namebuf)); + printf(" -> %s\n", namebuf); + + switch (rdata.type) { + case dns_rdatatype_soa: + printsoa(&rdata); + break; + default: + printf("\t"); + printrdata(&rdata); + } + dns_rdata_reset(&rdata); + loopresult = dns_rdataset_next(rdataset); + } + } + result = dns_message_nextname(msg, section); + if (result == ISC_R_NOMORE) + break; + else if (result != ISC_R_SUCCESS) { + return (result); + } + } + return (ISC_R_SUCCESS); +} + +void +received(int bytes, isc_sockaddr_t *from, dig_query_t *query) +{ + UNUSED(bytes); + UNUSED(from); + UNUSED(query); +} + +void +trying(char *frm, dig_lookup_t *lookup) { + UNUSED(frm); + UNUSED(lookup); + +} + +isc_result_t +printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { + char servtext[ISC_SOCKADDR_FORMATSIZE]; + + debug("printmessage()"); + + isc_sockaddr_format(&query->sockaddr, servtext, sizeof(servtext)); + printf("Server:\t\t%s\n", query->userarg); + printf("Address:\t%s\n", servtext); + + puts(""); + + if (!short_form) { + isc_boolean_t headers = ISC_TRUE; + puts("------------"); + /* detailheader(query, msg);*/ + detailsection(query, msg, headers, DNS_SECTION_QUESTION); + detailsection(query, msg, headers, DNS_SECTION_ANSWER); + detailsection(query, msg, headers, DNS_SECTION_AUTHORITY); + detailsection(query, msg, headers, DNS_SECTION_ADDITIONAL); + puts("------------"); + } + + if (msg->rcode != 0) { + char nametext[DNS_NAME_FORMATSIZE]; + dns_name_format(query->lookup->name, + nametext, sizeof(nametext)); + printf("** server can't find %s: %s\n", + (msg->rcode != dns_rcode_nxdomain) ? nametext : + query->lookup->textname, rcode_totext(msg->rcode)); + debug("returning with rcode == 0"); + return (ISC_R_SUCCESS); + } + + if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0) + puts("Non-authoritative answer:"); + if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) + printsection(query, msg, headers, DNS_SECTION_ANSWER); + else + printf("*** Can't find %s: No answer\n", + query->lookup->textname); + + if (((msg->flags & DNS_MESSAGEFLAG_AA) == 0) && + (query->lookup->rdtype != dns_rdatatype_a)) { + puts("\nAuthoritative answers can be found from:"); + printsection(query, msg, headers, + DNS_SECTION_AUTHORITY); + printsection(query, msg, headers, + DNS_SECTION_ADDITIONAL); + } + return (ISC_R_SUCCESS); +} + +static void +show_settings(isc_boolean_t full, isc_boolean_t serv_only) { + dig_server_t *srv; + isc_sockaddr_t sockaddr; + dig_searchlist_t *listent; + isc_result_t result; + + srv = ISC_LIST_HEAD(server_list); + + while (srv != NULL) { + char sockstr[ISC_SOCKADDR_FORMATSIZE]; + + result = get_address(srv->servername, port, &sockaddr); + check_result(result, "get_address"); + + isc_sockaddr_format(&sockaddr, sockstr, sizeof(sockstr)); + printf("Default server: %s\nAddress: %s\n", + srv->userarg, sockstr); + if (!full) + return; + srv = ISC_LIST_NEXT(srv, link); + } + if (serv_only) + return; + printf("\nSet options:\n"); + printf(" %s\t\t\t%s\t\t%s\n", + tcpmode ? "vc" : "novc", + short_form ? "nodebug" : "debug", + debugging ? "d2" : "nod2"); + printf(" %s\t\t%s\n", + usesearch ? "search" : "nosearch", + recurse ? "recurse" : "norecurse"); + printf(" timeout = %d\t\tretry = %d\tport = %d\n", + timeout, tries, port); + printf(" querytype = %-8s\tclass = %s\n", deftype, defclass); + printf(" srchlist = "); + for (listent = ISC_LIST_HEAD(search_list); + listent != NULL; + listent = ISC_LIST_NEXT(listent, link)) { + printf("%s", listent->origin); + if (ISC_LIST_NEXT(listent, link) != NULL) + printf("/"); + } + printf("\n"); +} + +static isc_boolean_t +testtype(char *typetext) { + isc_result_t result; + isc_textregion_t tr; + dns_rdatatype_t rdtype; + + tr.base = typetext; + tr.length = strlen(typetext); + result = dns_rdatatype_fromtext(&rdtype, &tr); + if (result == ISC_R_SUCCESS) + return (ISC_TRUE); + else { + printf("unknown query type: %s\n", typetext); + return (ISC_FALSE); + } +} + +static isc_boolean_t +testclass(char *typetext) { + isc_result_t result; + isc_textregion_t tr; + dns_rdataclass_t rdclass; + + tr.base = typetext; + tr.length = strlen(typetext); + result = dns_rdataclass_fromtext(&rdclass, &tr); + if (result == ISC_R_SUCCESS) + return (ISC_TRUE); + else { + printf("unknown query class: %s\n", typetext); + return (ISC_FALSE); + } +} + +static void +safecpy(char *dest, char *src, int size) { + strncpy(dest, src, size); + dest[size-1] = 0; +} + +static isc_result_t +parse_uint(isc_uint32_t *uip, const char *value, isc_uint32_t max, + const char *desc) { + isc_uint32_t n; + isc_result_t result = isc_parse_uint32(&n, value, 10); + if (result == ISC_R_SUCCESS && n > max) + result = ISC_R_RANGE; + if (result != ISC_R_SUCCESS) { + printf("invalid %s '%s': %s\n", desc, + value, isc_result_totext(result)); + return result; + } + *uip = n; + return (ISC_R_SUCCESS); +} + +static void +set_port(const char *value) { + isc_uint32_t n; + isc_result_t result = parse_uint(&n, value, 65535, "port"); + if (result == ISC_R_SUCCESS) + port = (isc_uint16_t) n; +} + +static void +set_timeout(const char *value) { + isc_uint32_t n; + isc_result_t result = parse_uint(&n, value, UINT_MAX, "timeout"); + if (result == ISC_R_SUCCESS) + timeout = n; +} + +static void +set_tries(const char *value) { + isc_uint32_t n; + isc_result_t result = parse_uint(&n, value, INT_MAX, "tries"); + if (result == ISC_R_SUCCESS) + tries = n; +} + +static void +setoption(char *opt) { + if (strncasecmp(opt, "all", 4) == 0) { + show_settings(ISC_TRUE, ISC_FALSE); + } else if (strncasecmp(opt, "class=", 6) == 0) { + if (testclass(&opt[6])) + safecpy(defclass, &opt[6], sizeof(defclass)); + } else if (strncasecmp(opt, "cl=", 3) == 0) { + if (testclass(&opt[3])) + safecpy(defclass, &opt[3], sizeof(defclass)); + } else if (strncasecmp(opt, "type=", 5) == 0) { + if (testtype(&opt[5])) + safecpy(deftype, &opt[5], sizeof(deftype)); + } else if (strncasecmp(opt, "ty=", 3) == 0) { + if (testtype(&opt[3])) + safecpy(deftype, &opt[3], sizeof(deftype)); + } else if (strncasecmp(opt, "querytype=", 10) == 0) { + if (testtype(&opt[10])) + safecpy(deftype, &opt[10], sizeof(deftype)); + } else if (strncasecmp(opt, "query=", 6) == 0) { + if (testtype(&opt[6])) + safecpy(deftype, &opt[6], sizeof(deftype)); + } else if (strncasecmp(opt, "qu=", 3) == 0) { + if (testtype(&opt[3])) + safecpy(deftype, &opt[3], sizeof(deftype)); + } else if (strncasecmp(opt, "q=", 2) == 0) { + if (testtype(&opt[2])) + safecpy(deftype, &opt[2], sizeof(deftype)); + } else if (strncasecmp(opt, "domain=", 7) == 0) { + safecpy(domainopt, &opt[7], sizeof(domainopt)); + set_search_domain(domainopt); + usesearch = ISC_TRUE; + } else if (strncasecmp(opt, "do=", 3) == 0) { + safecpy(domainopt, &opt[3], sizeof(domainopt)); + set_search_domain(domainopt); + usesearch = ISC_TRUE; + } else if (strncasecmp(opt, "port=", 5) == 0) { + set_port(&opt[5]); + } else if (strncasecmp(opt, "po=", 3) == 0) { + set_port(&opt[3]); + } else if (strncasecmp(opt, "timeout=", 8) == 0) { + set_timeout(&opt[8]); + } else if (strncasecmp(opt, "t=", 2) == 0) { + set_timeout(&opt[2]); + } else if (strncasecmp(opt, "rec", 3) == 0) { + recurse = ISC_TRUE; + } else if (strncasecmp(opt, "norec", 5) == 0) { + recurse = ISC_FALSE; + } else if (strncasecmp(opt, "retry=", 6) == 0) { + set_tries(&opt[6]); + } else if (strncasecmp(opt, "ret=", 4) == 0) { + set_tries(&opt[4]); + } else if (strncasecmp(opt, "def", 3) == 0) { + usesearch = ISC_TRUE; + } else if (strncasecmp(opt, "nodef", 5) == 0) { + usesearch = ISC_FALSE; + } else if (strncasecmp(opt, "vc", 3) == 0) { + tcpmode = ISC_TRUE; + } else if (strncasecmp(opt, "novc", 5) == 0) { + tcpmode = ISC_FALSE; + } else if (strncasecmp(opt, "deb", 3) == 0) { + short_form = ISC_FALSE; + showsearch = ISC_TRUE; + } else if (strncasecmp(opt, "nodeb", 5) == 0) { + short_form = ISC_TRUE; + showsearch = ISC_FALSE; + } else if (strncasecmp(opt, "d2", 2) == 0) { + debugging = ISC_TRUE; + } else if (strncasecmp(opt, "nod2", 4) == 0) { + debugging = ISC_FALSE; + } else if (strncasecmp(opt, "search", 3) == 0) { + usesearch = ISC_TRUE; + } else if (strncasecmp(opt, "nosearch", 5) == 0) { + usesearch = ISC_FALSE; + } else if (strncasecmp(opt, "sil", 3) == 0) { + /* deprecation_msg = ISC_FALSE; */ + } else if (strncasecmp(opt, "fail", 3) == 0) { + nofail=ISC_FALSE; + } else if (strncasecmp(opt, "nofail", 3) == 0) { + nofail=ISC_TRUE; + } else { + printf("*** Invalid option: %s\n", opt); + } +} + +static void +addlookup(char *opt) { + dig_lookup_t *lookup; + isc_result_t result; + isc_textregion_t tr; + dns_rdatatype_t rdtype; + dns_rdataclass_t rdclass; + char store[MXNAME]; + + debug("addlookup()"); + tr.base = deftype; + tr.length = strlen(deftype); + result = dns_rdatatype_fromtext(&rdtype, &tr); + if (result != ISC_R_SUCCESS) { + printf("unknown query type: %s\n", deftype); + rdclass = dns_rdatatype_a; + } + tr.base = defclass; + tr.length = strlen(defclass); + result = dns_rdataclass_fromtext(&rdclass, &tr); + if (result != ISC_R_SUCCESS) { + printf("unknown query class: %s\n", defclass); + rdclass = dns_rdataclass_in; + } + lookup = make_empty_lookup(); + if (get_reverse(store, sizeof(store), opt, lookup->ip6_int, ISC_TRUE) + == ISC_R_SUCCESS) { + safecpy(lookup->textname, store, sizeof(lookup->textname)); + lookup->rdtype = dns_rdatatype_ptr; + lookup->rdtypeset = ISC_TRUE; + } else { + safecpy(lookup->textname, opt, sizeof(lookup->textname)); + lookup->rdtype = rdtype; + lookup->rdtypeset = ISC_TRUE; + } + lookup->rdclass = rdclass; + lookup->rdclassset = ISC_TRUE; + lookup->trace = ISC_FALSE; + lookup->trace_root = lookup->trace; + lookup->ns_search_only = ISC_FALSE; + lookup->identify = identify; + lookup->recurse = recurse; + lookup->aaonly = aaonly; + lookup->retries = tries; + lookup->udpsize = 0; + lookup->comments = comments; + lookup->tcp_mode = tcpmode; + lookup->stats = stats; + lookup->section_question = section_question; + lookup->section_answer = section_answer; + lookup->section_authority = section_authority; + lookup->section_additional = section_additional; + lookup->new_search = ISC_TRUE; + if (nofail) + lookup->servfail_stops = ISC_FALSE; + ISC_LIST_INIT(lookup->q); + ISC_LINK_INIT(lookup, link); + ISC_LIST_APPEND(lookup_list, lookup, link); + lookup->origin = NULL; + ISC_LIST_INIT(lookup->my_server_list); + debug("looking up %s", lookup->textname); +} + +static void +get_next_command(void) { + char *buf; + char *ptr, *arg; + char *input; + + fflush(stdout); + buf = isc_mem_allocate(mctx, COMMSIZE); + if (buf == NULL) + fatal("memory allocation failure"); + fputs("> ", stderr); + fflush(stderr); + isc_app_block(); + ptr = fgets(buf, COMMSIZE, stdin); + isc_app_unblock(); + if (ptr == NULL) { + in_use = ISC_FALSE; + goto cleanup; + } + input = buf; + ptr = next_token(&input, " \t\r\n"); + if (ptr == NULL) + goto cleanup; + arg = next_token(&input, " \t\r\n"); + if ((strcasecmp(ptr, "set") == 0) && + (arg != NULL)) + setoption(arg); + else if ((strcasecmp(ptr, "server") == 0) || + (strcasecmp(ptr, "lserver") == 0)) { + isc_app_block(); + set_nameserver(arg); + check_ra = ISC_FALSE; + isc_app_unblock(); + show_settings(ISC_TRUE, ISC_TRUE); + } else if (strcasecmp(ptr, "exit") == 0) { + in_use = ISC_FALSE; + goto cleanup; + } else if (strcasecmp(ptr, "help") == 0 || + strcasecmp(ptr, "?") == 0) { + printf("The '%s' command is not yet implemented.\n", ptr); + goto cleanup; + } else if (strcasecmp(ptr, "finger") == 0 || + strcasecmp(ptr, "root") == 0 || + strcasecmp(ptr, "ls") == 0 || + strcasecmp(ptr, "view") == 0) { + printf("The '%s' command is not implemented.\n", ptr); + goto cleanup; + } else + addlookup(ptr); + cleanup: + isc_mem_free(mctx, buf); +} + +static void +parse_args(int argc, char **argv) { + isc_boolean_t have_lookup = ISC_FALSE; + + usesearch = ISC_TRUE; + for (argc--, argv++; argc > 0; argc--, argv++) { + debug("main parsing %s", argv[0]); + if (argv[0][0] == '-') { + if (argv[0][1] != 0) + setoption(&argv[0][1]); + else + have_lookup = ISC_TRUE; + } else { + if (!have_lookup) { + have_lookup = ISC_TRUE; + in_use = ISC_TRUE; + addlookup(argv[0]); + } else { + set_nameserver(argv[0]); + check_ra = ISC_FALSE; + } + } + } +} + +static void +flush_lookup_list(void) { + dig_lookup_t *l, *lp; + dig_query_t *q, *qp; + dig_server_t *s, *sp; + + lookup_counter = 0; + l = ISC_LIST_HEAD(lookup_list); + while (l != NULL) { + q = ISC_LIST_HEAD(l->q); + while (q != NULL) { + if (q->sock != NULL) { + isc_socket_cancel(q->sock, NULL, + ISC_SOCKCANCEL_ALL); + isc_socket_detach(&q->sock); + } + if (ISC_LINK_LINKED(&q->recvbuf, link)) + ISC_LIST_DEQUEUE(q->recvlist, &q->recvbuf, + link); + if (ISC_LINK_LINKED(&q->lengthbuf, link)) + ISC_LIST_DEQUEUE(q->lengthlist, &q->lengthbuf, + link); + isc_buffer_invalidate(&q->recvbuf); + isc_buffer_invalidate(&q->lengthbuf); + qp = q; + q = ISC_LIST_NEXT(q, link); + ISC_LIST_DEQUEUE(l->q, qp, link); + isc_mem_free(mctx, qp); + } + s = ISC_LIST_HEAD(l->my_server_list); + while (s != NULL) { + sp = s; + s = ISC_LIST_NEXT(s, link); + ISC_LIST_DEQUEUE(l->my_server_list, sp, link); + isc_mem_free(mctx, sp); + + } + if (l->sendmsg != NULL) + dns_message_destroy(&l->sendmsg); + if (l->timer != NULL) + isc_timer_detach(&l->timer); + lp = l; + l = ISC_LIST_NEXT(l, link); + ISC_LIST_DEQUEUE(lookup_list, lp, link); + isc_mem_free(mctx, lp); + } +} + +static void +getinput(isc_task_t *task, isc_event_t *event) { + UNUSED(task); + if (global_event == NULL) + global_event = event; + while (in_use) { + get_next_command(); + if (ISC_LIST_HEAD(lookup_list) != NULL) { + start_lookup(); + return; + } + } + isc_app_shutdown(); +} + +int +main(int argc, char **argv) { + isc_result_t result; + + ISC_LIST_INIT(lookup_list); + ISC_LIST_INIT(server_list); + ISC_LIST_INIT(search_list); + + check_ra = ISC_TRUE; + + result = isc_app_start(); + check_result(result, "isc_app_start"); + + setup_libs(); + progname = argv[0]; + + parse_args(argc, argv); + + setup_system(); + if (domainopt[0] != '\0') + set_search_domain(domainopt); + if (in_use) + result = isc_app_onrun(mctx, global_task, onrun_callback, + NULL); + else + result = isc_app_onrun(mctx, global_task, getinput, NULL); + check_result(result, "isc_app_onrun"); + in_use = ISC_TF(!in_use); + + (void)isc_app_run(); + + puts(""); + debug("done, and starting to shut down"); + if (global_event != NULL) + isc_event_free(&global_event); + cancel_all(); + destroy_libs(); + isc_app_finish(); + + return (0); +} diff --git a/contrib/bind-9.5.2/bin/dig/nslookup.html b/contrib/bind-9.5.2/bin/dig/nslookup.html new file mode 100644 index 0000000000..8009044186 --- /dev/null +++ b/contrib/bind-9.5.2/bin/dig/nslookup.html @@ -0,0 +1,307 @@ + + + + + +nslookup + + +
+
+
+

Name

+

nslookup — query Internet name servers interactively

+
+
+

Synopsis

+

nslookup [-option] [name | -] [server]

+
+
+

DESCRIPTION

+

Nslookup + is a program to query Internet domain name servers. Nslookup + has two modes: interactive and non-interactive. Interactive mode allows + the user to query name servers for information about various hosts and + domains or to print a list of hosts in a domain. Non-interactive mode + is + used to print just the name and requested information for a host or + domain. +

+
+
+

ARGUMENTS

+

+ Interactive mode is entered in the following cases: +

+
    +
  1. + when no arguments are given (the default name server will be used) +

  2. +
  3. + when the first argument is a hyphen (-) and the second argument is + the host name or Internet address of a name server. +

  4. +
+

+

+

+ Non-interactive mode is used when the name or Internet address of the + host to be looked up is given as the first argument. The optional second + argument specifies the host name or address of a name server. +

+

+ Options can also be specified on the command line if they precede the + arguments and are prefixed with a hyphen. For example, to + change the default query type to host information, and the initial + timeout to 10 seconds, type: +

+
+nslookup -query=hinfo  -timeout=10
+
+

+

+
+
+

INTERACTIVE COMMANDS

+
+
host [server]
+
+

+ Look up information for host using the current default server or + using server, if specified. If host is an Internet address and + the query type is A or PTR, the name of the host is returned. + If host is a name and does not have a trailing period, the + search list is used to qualify the name. +

+

+ To look up a host not in the current domain, append a period to + the name. +

+
+
server domain
+

+
lserver domain
+

+ Change the default server to domain; lserver uses the initial + server to look up information about domain, while server uses + the current default server. If an authoritative answer can't be + found, the names of servers that might have the answer are + returned. +

+
root
+

+ not implemented +

+
finger
+

+ not implemented +

+
ls
+

+ not implemented +

+
view
+

+ not implemented +

+
help
+

+ not implemented +

+
?
+

+ not implemented +

+
exit
+

+ Exits the program. +

+
set + keyword[=value]
+
+

+ This command is used to change state information that affects + the lookups. Valid keywords are: +

+
+
all
+

+ Prints the current values of the frequently used + options to set. + Information about the current default + server and host is also printed. +

+
class=value
+
+

+ Change the query class to one of: +

+
+
IN
+

+ the Internet class +

+
CH
+

+ the Chaos class +

+
HS
+

+ the Hesiod class +

+
ANY
+

+ wildcard +

+
+

+ The class specifies the protocol group of the information. + +

+

+ (Default = IN; abbreviation = cl) +

+
+
+ [no]debug
+
+

+ Turn on or off the display of the full response packet and + any intermediate response packets when searching. +

+

+ (Default = nodebug; abbreviation = [no]deb) +

+
+
+ [no]d2
+
+

+ Turn debugging mode on or off. This displays more about + what nslookup is doing. +

+

+ (Default = nod2) +

+
+
domain=name
+

+ Sets the search list to name. +

+
+ [no]search
+
+

+ If the lookup request contains at least one period but + doesn't end with a trailing period, append the domain + names in the domain search list to the request until an + answer is received. +

+

+ (Default = search) +

+
+
port=value
+
+

+ Change the default TCP/UDP name server port to value. +

+

+ (Default = 53; abbreviation = po) +

+
+
querytype=value
+

+
type=value
+
+

+ Change the type of the information query. +

+

+ (Default = A; abbreviations = q, ty) +

+
+
+ [no]recurse
+
+

+ Tell the name server to query other servers if it does not + have the + information. +

+

+ (Default = recurse; abbreviation = [no]rec) +

+
+
retry=number
+

+ Set the number of retries to number. +

+
timeout=number
+

+ Change the initial timeout interval for waiting for a + reply to number seconds. +

+
+ [no]vc
+
+

+ Always use a virtual circuit when sending requests to the + server. +

+

+ (Default = novc) +

+
+
+ [no]fail
+
+

+ Try the next nameserver if a nameserver responds with + SERVFAIL or a referral (nofail) or terminate query + (fail) on such a response. +

+

+ (Default = nofail) +

+
+
+

+

+
+
+
+
+

FILES

+

/etc/resolv.conf +

+
+
+

SEE ALSO

+

dig(1), + host(1), + named(8). +

+
+
+

Author

+

+ Andrew Cherenson +

+
+
+ diff --git a/contrib/bind-9.5.2/bin/dnssec/dnssec-keygen.8 b/contrib/bind-9.5.2/bin/dnssec/dnssec-keygen.8 new file mode 100644 index 0000000000..edeee13e16 --- /dev/null +++ b/contrib/bind-9.5.2/bin/dnssec/dnssec-keygen.8 @@ -0,0 +1,200 @@ +.\" Copyright (C) 2004, 2005, 2007, 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 +.\" 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: dnssec-keygen.8,v 1.38.130.3 2009/07/11 01:43:27 tbox Exp $ +.\" +.hy 0 +.ad l +.\" Title: dnssec\-keygen +.\" Author: +.\" Generator: DocBook XSL Stylesheets v1.71.1 +.\" Date: June 30, 2000 +.\" Manual: BIND9 +.\" Source: BIND9 +.\" +.TH "DNSSEC\-KEYGEN" "8" "June 30, 2000" "BIND9" "BIND9" +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.SH "NAME" +dnssec\-keygen \- DNSSEC key generation tool +.SH "SYNOPSIS" +.HP 14 +\fBdnssec\-keygen\fR {\-a\ \fIalgorithm\fR} {\-b\ \fIkeysize\fR} {\-n\ \fInametype\fR} [\fB\-c\ \fR\fB\fIclass\fR\fR] [\fB\-e\fR] [\fB\-f\ \fR\fB\fIflag\fR\fR] [\fB\-g\ \fR\fB\fIgenerator\fR\fR] [\fB\-h\fR] [\fB\-k\fR] [\fB\-p\ \fR\fB\fIprotocol\fR\fR] [\fB\-r\ \fR\fB\fIrandomdev\fR\fR] [\fB\-s\ \fR\fB\fIstrength\fR\fR] [\fB\-t\ \fR\fB\fItype\fR\fR] [\fB\-v\ \fR\fB\fIlevel\fR\fR] {name} +.SH "DESCRIPTION" +.PP +\fBdnssec\-keygen\fR +generates keys for DNSSEC (Secure DNS), as defined in RFC 2535 and RFC 4034. It can also generate keys for use with TSIG (Transaction Signatures), as defined in RFC 2845. +.SH "OPTIONS" +.PP +\-a \fIalgorithm\fR +.RS 4 +Selects the cryptographic algorithm. The value of +\fBalgorithm\fR +must be one of RSAMD5 (RSA) or RSASHA1, DSA, DH (Diffie Hellman), or HMAC\-MD5. These values are case insensitive. +.sp +Note 1: that for DNSSEC, RSASHA1 is a mandatory to implement algorithm, and DSA is recommended. For TSIG, HMAC\-MD5 is mandatory. +.sp +Note 2: HMAC\-MD5 and DH automatically set the \-k flag. +.RE +.PP +\-b \fIkeysize\fR +.RS 4 +Specifies the number of bits in the key. The choice of key size depends on the algorithm used. RSAMD5 / RSASHA1 keys must be between 512 and 2048 bits. Diffie Hellman keys must be between 128 and 4096 bits. DSA keys must be between 512 and 1024 bits and an exact multiple of 64. HMAC\-MD5 keys must be between 1 and 512 bits. +.RE +.PP +\-n \fInametype\fR +.RS 4 +Specifies the owner type of the key. The value of +\fBnametype\fR +must either be ZONE (for a DNSSEC zone key (KEY/DNSKEY)), HOST or ENTITY (for a key associated with a host (KEY)), USER (for a key associated with a user(KEY)) or OTHER (DNSKEY). These values are case insensitive. Defaults to ZONE for DNSKEY generation. +.RE +.PP +\-c \fIclass\fR +.RS 4 +Indicates that the DNS record containing the key should have the specified class. If not specified, class IN is used. +.RE +.PP +\-e +.RS 4 +If generating an RSAMD5/RSASHA1 key, use a large exponent. +.RE +.PP +\-f \fIflag\fR +.RS 4 +Set the specified flag in the flag field of the KEY/DNSKEY record. The only recognized flag is KSK (Key Signing Key) DNSKEY. +.RE +.PP +\-g \fIgenerator\fR +.RS 4 +If generating a Diffie Hellman key, use this generator. Allowed values are 2 and 5. If no generator is specified, a known prime from RFC 2539 will be used if possible; otherwise the default is 2. +.RE +.PP +\-h +.RS 4 +Prints a short summary of the options and arguments to +\fBdnssec\-keygen\fR. +.RE +.PP +\-k +.RS 4 +Generate KEY records rather than DNSKEY records. +.RE +.PP +\-p \fIprotocol\fR +.RS 4 +Sets the protocol value for the generated key. The protocol is a number between 0 and 255. The default is 3 (DNSSEC). Other possible values for this argument are listed in RFC 2535 and its successors. +.RE +.PP +\-r \fIrandomdev\fR +.RS 4 +Specifies the source of randomness. If the operating system does not provide a +\fI/dev/random\fR +or equivalent device, the default source of randomness is keyboard input. +\fIrandomdev\fR +specifies the name of a character device or file containing random data to be used instead of the default. The special value +\fIkeyboard\fR +indicates that keyboard input should be used. +.RE +.PP +\-s \fIstrength\fR +.RS 4 +Specifies the strength value of the key. The strength is a number between 0 and 15, and currently has no defined purpose in DNSSEC. +.RE +.PP +\-t \fItype\fR +.RS 4 +Indicates the use of the key. +\fBtype\fR +must be one of AUTHCONF, NOAUTHCONF, NOAUTH, or NOCONF. The default is AUTHCONF. AUTH refers to the ability to authenticate data, and CONF the ability to encrypt data. +.RE +.PP +\-v \fIlevel\fR +.RS 4 +Sets the debugging level. +.RE +.SH "GENERATED KEYS" +.PP +When +\fBdnssec\-keygen\fR +completes successfully, it prints a string of the form +\fIKnnnn.+aaa+iiiii\fR +to the standard output. This is an identification string for the key it has generated. +.TP 4 +\(bu +\fInnnn\fR +is the key name. +.TP 4 +\(bu +\fIaaa\fR +is the numeric representation of the algorithm. +.TP 4 +\(bu +\fIiiiii\fR +is the key identifier (or footprint). +.PP +\fBdnssec\-keygen\fR +creates two files, with names based on the printed string. +\fIKnnnn.+aaa+iiiii.key\fR +contains the public key, and +\fIKnnnn.+aaa+iiiii.private\fR +contains the private key. +.PP +The +\fI.key\fR +file contains a DNS KEY record that can be inserted into a zone file (directly or with a $INCLUDE statement). +.PP +The +\fI.private\fR +file contains algorithm\-specific fields. For obvious security reasons, this file does not have general read permission. +.PP +Both +\fI.key\fR +and +\fI.private\fR +files are generated for symmetric encryption algorithms such as HMAC\-MD5, even though the public and private key are equivalent. +.SH "EXAMPLE" +.PP +To generate a 768\-bit DSA key for the domain +\fBexample.com\fR, the following command would be issued: +.PP +\fBdnssec\-keygen \-a DSA \-b 768 \-n ZONE example.com\fR +.PP +The command would print a string of the form: +.PP +\fBKexample.com.+003+26160\fR +.PP +In this example, +\fBdnssec\-keygen\fR +creates the files +\fIKexample.com.+003+26160.key\fR +and +\fIKexample.com.+003+26160.private\fR. +.SH "SEE ALSO" +.PP +\fBdnssec\-signzone\fR(8), +BIND 9 Administrator Reference Manual, +RFC 2539, +RFC 2845, +RFC 4033. +.SH "AUTHOR" +.PP +Internet Systems Consortium +.SH "COPYRIGHT" +Copyright \(co 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") +.br +Copyright \(co 2000\-2003 Internet Software Consortium. +.br diff --git a/contrib/bind-9.5.2/bin/dnssec/dnssec-keygen.c b/contrib/bind-9.5.2/bin/dnssec/dnssec-keygen.c new file mode 100644 index 0000000000..3fd29b379c --- /dev/null +++ b/contrib/bind-9.5.2/bin/dnssec/dnssec-keygen.c @@ -0,0 +1,535 @@ +/* + * Portions Copyright (C) 2004-2007 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 + * 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 AND NETWORK ASSOCIATES 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. + * + * Portions Copyright (C) 1995-2000 by Network Associates, Inc. + * + * 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 AND NETWORK ASSOCIATES 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: dnssec-keygen.c,v 1.79 2007/08/28 07:20:42 tbox Exp $ */ + +/*! \file */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "dnssectool.h" + +#define MAX_RSA 4096 /* should be long enough... */ + +const char *program = "dnssec-keygen"; +int verbose; + +static const char *algs = "RSA | RSAMD5 | DH | DSA | RSASHA1 | HMAC-MD5 |" + " HMAC-SHA1 | HMAC-SHA224 | HMAC-SHA256 | " + " HMAC-SHA384 | HMAC-SHA512"; + +static isc_boolean_t +dsa_size_ok(int size) { + return (ISC_TF(size >= 512 && size <= 1024 && size % 64 == 0)); +} + +static void +usage(void) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " %s -a alg -b bits [-n type] [options] name\n\n", + program); + fprintf(stderr, "Version: %s\n", VERSION); + fprintf(stderr, "Required options:\n"); + fprintf(stderr, " -a algorithm: %s\n", algs); + fprintf(stderr, " -b key size, in bits:\n"); + fprintf(stderr, " RSAMD5:\t\t[512..%d]\n", MAX_RSA); + fprintf(stderr, " RSASHA1:\t\t[512..%d]\n", MAX_RSA); + fprintf(stderr, " DH:\t\t[128..4096]\n"); + fprintf(stderr, " DSA:\t\t[512..1024] and divisible by 64\n"); + fprintf(stderr, " HMAC-MD5:\t[1..512]\n"); + fprintf(stderr, " HMAC-SHA1:\t[1..160]\n"); + fprintf(stderr, " HMAC-SHA224:\t[1..224]\n"); + fprintf(stderr, " HMAC-SHA256:\t[1..256]\n"); + fprintf(stderr, " HMAC-SHA384:\t[1..384]\n"); + fprintf(stderr, " HMAC-SHA512:\t[1..512]\n"); + fprintf(stderr, " -n nametype: ZONE | HOST | ENTITY | USER | OTHER\n"); + fprintf(stderr, " (DNSKEY generation defaults to ZONE\n"); + fprintf(stderr, " name: owner of the key\n"); + fprintf(stderr, "Other options:\n"); + fprintf(stderr, " -c (default: IN)\n"); + fprintf(stderr, " -d (0 => max, default)\n"); + fprintf(stderr, " -e use large exponent (RSAMD5/RSASHA1 only)\n"); + fprintf(stderr, " -f keyflag: KSK\n"); + fprintf(stderr, " -g use specified generator " + "(DH only)\n"); + fprintf(stderr, " -t : " + "AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF " + "(default: AUTHCONF)\n"); + fprintf(stderr, " -p : " + "default: 3 [dnssec]\n"); + fprintf(stderr, " -s strength value this key signs DNS " + "records with (default: 0)\n"); + fprintf(stderr, " -r : a file containing random data\n"); + fprintf(stderr, " -v \n"); + fprintf(stderr, " -k : generate a TYPE=KEY key\n"); + fprintf(stderr, "Output:\n"); + fprintf(stderr, " K++.key, " + "K++.private\n"); + + exit (-1); +} + +int +main(int argc, char **argv) { + char *algname = NULL, *nametype = NULL, *type = NULL; + char *classname = NULL; + char *endp; + dst_key_t *key = NULL, *oldkey; + dns_fixedname_t fname; + dns_name_t *name; + isc_uint16_t flags = 0, ksk = 0; + dns_secalg_t alg; + isc_boolean_t conflict = ISC_FALSE, null_key = ISC_FALSE; + isc_mem_t *mctx = NULL; + int ch, rsa_exp = 0, generator = 0, param = 0; + int protocol = -1, size = -1, signatory = 0; + isc_result_t ret; + isc_textregion_t r; + char filename[255]; + isc_buffer_t buf; + isc_log_t *log = NULL; + isc_entropy_t *ectx = NULL; + dns_rdataclass_t rdclass; + int options = DST_TYPE_PRIVATE | DST_TYPE_PUBLIC; + int dbits = 0; + + if (argc == 1) + usage(); + + RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS); + + dns_result_register(); + + isc_commandline_errprint = ISC_FALSE; + + while ((ch = isc_commandline_parse(argc, argv, + "a:b:c:d:ef:g:kn:t:p:s:r:v:h")) != -1) + { + switch (ch) { + case 'a': + algname = isc_commandline_argument; + break; + case 'b': + size = strtol(isc_commandline_argument, &endp, 10); + if (*endp != '\0' || size < 0) + fatal("-b requires a non-negative number"); + break; + case 'c': + classname = isc_commandline_argument; + break; + case 'd': + dbits = strtol(isc_commandline_argument, &endp, 10); + if (*endp != '\0' || dbits < 0) + fatal("-d requires a non-negative number"); + break; + case 'e': + rsa_exp = 1; + break; + case 'f': + if (strcasecmp(isc_commandline_argument, "KSK") == 0) + ksk = DNS_KEYFLAG_KSK; + else + fatal("unknown flag '%s'", + isc_commandline_argument); + break; + case 'g': + generator = strtol(isc_commandline_argument, + &endp, 10); + if (*endp != '\0' || generator <= 0) + fatal("-g requires a positive number"); + break; + case 'k': + options |= DST_TYPE_KEY; + break; + case 'n': + nametype = isc_commandline_argument; + break; + case 't': + type = isc_commandline_argument; + break; + case 'p': + protocol = strtol(isc_commandline_argument, &endp, 10); + if (*endp != '\0' || protocol < 0 || protocol > 255) + fatal("-p must be followed by a number " + "[0..255]"); + break; + case 's': + signatory = strtol(isc_commandline_argument, + &endp, 10); + if (*endp != '\0' || signatory < 0 || signatory > 15) + fatal("-s must be followed by a number " + "[0..15]"); + break; + case 'r': + setup_entropy(mctx, isc_commandline_argument, &ectx); + break; + case 'v': + endp = NULL; + verbose = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') + fatal("-v must be followed by a number"); + break; + + case '?': + if (isc_commandline_option != '?') + fprintf(stderr, "%s: invalid argument -%c\n", + program, isc_commandline_option); + case 'h': + usage(); + + default: + fprintf(stderr, "%s: unhandled option -%c\n", + program, isc_commandline_option); + exit(1); + } + } + + if (ectx == NULL) + setup_entropy(mctx, NULL, &ectx); + ret = dst_lib_init(mctx, ectx, + ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY); + if (ret != ISC_R_SUCCESS) + fatal("could not initialize dst"); + + setup_logging(verbose, mctx, &log); + + if (argc < isc_commandline_index + 1) + fatal("the key name was not specified"); + if (argc > isc_commandline_index + 1) + fatal("extraneous arguments"); + + if (algname == NULL) + fatal("no algorithm was specified"); + if (strcasecmp(algname, "RSA") == 0) { + fprintf(stderr, "The use of RSA (RSAMD5) is not recommended.\n" + "If you still wish to use RSA (RSAMD5) please " + "specify \"-a RSAMD5\"\n"); + return (1); + } else if (strcasecmp(algname, "HMAC-MD5") == 0) { + options |= DST_TYPE_KEY; + alg = DST_ALG_HMACMD5; + } else if (strcasecmp(algname, "HMAC-SHA1") == 0) { + options |= DST_TYPE_KEY; + alg = DST_ALG_HMACSHA1; + } else if (strcasecmp(algname, "HMAC-SHA224") == 0) { + options |= DST_TYPE_KEY; + alg = DST_ALG_HMACSHA224; + } else if (strcasecmp(algname, "HMAC-SHA256") == 0) { + options |= DST_TYPE_KEY; + alg = DST_ALG_HMACSHA256; + } else if (strcasecmp(algname, "HMAC-SHA384") == 0) { + options |= DST_TYPE_KEY; + alg = DST_ALG_HMACSHA384; + } else if (strcasecmp(algname, "HMAC-SHA512") == 0) { + options |= DST_TYPE_KEY; + alg = DST_ALG_HMACSHA512; + } else { + r.base = algname; + r.length = strlen(algname); + ret = dns_secalg_fromtext(&alg, &r); + if (ret != ISC_R_SUCCESS) + fatal("unknown algorithm %s", algname); + if (alg == DST_ALG_DH) + options |= DST_TYPE_KEY; + } + + if (type != NULL && (options & DST_TYPE_KEY) != 0) { + if (strcasecmp(type, "NOAUTH") == 0) + flags |= DNS_KEYTYPE_NOAUTH; + else if (strcasecmp(type, "NOCONF") == 0) + flags |= DNS_KEYTYPE_NOCONF; + else if (strcasecmp(type, "NOAUTHCONF") == 0) { + flags |= (DNS_KEYTYPE_NOAUTH | DNS_KEYTYPE_NOCONF); + if (size < 0) + size = 0; + } + else if (strcasecmp(type, "AUTHCONF") == 0) + /* nothing */; + else + fatal("invalid type %s", type); + } + + if (size < 0) + fatal("key size not specified (-b option)"); + + switch (alg) { + case DNS_KEYALG_RSAMD5: + case DNS_KEYALG_RSASHA1: + if (size != 0 && (size < 512 || size > MAX_RSA)) + fatal("RSA key size %d out of range", size); + break; + case DNS_KEYALG_DH: + if (size != 0 && (size < 128 || size > 4096)) + fatal("DH key size %d out of range", size); + break; + case DNS_KEYALG_DSA: + if (size != 0 && !dsa_size_ok(size)) + fatal("invalid DSS key size: %d", size); + break; + case DST_ALG_HMACMD5: + if (size < 1 || size > 512) + fatal("HMAC-MD5 key size %d out of range", size); + if (dbits != 0 && (dbits < 80 || dbits > 128)) + fatal("HMAC-MD5 digest bits %d out of range", dbits); + if ((dbits % 8) != 0) + fatal("HMAC-MD5 digest bits %d not divisible by 8", + dbits); + break; + case DST_ALG_HMACSHA1: + if (size < 1 || size > 160) + fatal("HMAC-SHA1 key size %d out of range", size); + if (dbits != 0 && (dbits < 80 || dbits > 160)) + fatal("HMAC-SHA1 digest bits %d out of range", dbits); + if ((dbits % 8) != 0) + fatal("HMAC-SHA1 digest bits %d not divisible by 8", + dbits); + break; + case DST_ALG_HMACSHA224: + if (size < 1 || size > 224) + fatal("HMAC-SHA224 key size %d out of range", size); + if (dbits != 0 && (dbits < 112 || dbits > 224)) + fatal("HMAC-SHA224 digest bits %d out of range", dbits); + if ((dbits % 8) != 0) + fatal("HMAC-SHA224 digest bits %d not divisible by 8", + dbits); + break; + case DST_ALG_HMACSHA256: + if (size < 1 || size > 256) + fatal("HMAC-SHA256 key size %d out of range", size); + if (dbits != 0 && (dbits < 128 || dbits > 256)) + fatal("HMAC-SHA256 digest bits %d out of range", dbits); + if ((dbits % 8) != 0) + fatal("HMAC-SHA256 digest bits %d not divisible by 8", + dbits); + break; + case DST_ALG_HMACSHA384: + if (size < 1 || size > 384) + fatal("HMAC-384 key size %d out of range", size); + if (dbits != 0 && (dbits < 192 || dbits > 384)) + fatal("HMAC-SHA384 digest bits %d out of range", dbits); + if ((dbits % 8) != 0) + fatal("HMAC-SHA384 digest bits %d not divisible by 8", + dbits); + break; + case DST_ALG_HMACSHA512: + if (size < 1 || size > 512) + fatal("HMAC-SHA512 key size %d out of range", size); + if (dbits != 0 && (dbits < 256 || dbits > 512)) + fatal("HMAC-SHA512 digest bits %d out of range", dbits); + if ((dbits % 8) != 0) + fatal("HMAC-SHA512 digest bits %d not divisible by 8", + dbits); + break; + } + + if (!(alg == DNS_KEYALG_RSAMD5 || alg == DNS_KEYALG_RSASHA1) && + rsa_exp != 0) + fatal("specified RSA exponent for a non-RSA key"); + + if (alg != DNS_KEYALG_DH && generator != 0) + fatal("specified DH generator for a non-DH key"); + + if (nametype == NULL) { + if ((options & DST_TYPE_KEY) != 0) /* KEY / HMAC */ + fatal("no nametype specified"); + flags |= DNS_KEYOWNER_ZONE; /* DNSKEY */ + } else if (strcasecmp(nametype, "zone") == 0) + flags |= DNS_KEYOWNER_ZONE; + else if ((options & DST_TYPE_KEY) != 0) { /* KEY / HMAC */ + if (strcasecmp(nametype, "host") == 0 || + strcasecmp(nametype, "entity") == 0) + flags |= DNS_KEYOWNER_ENTITY; + else if (strcasecmp(nametype, "user") == 0) + flags |= DNS_KEYOWNER_USER; + else + fatal("invalid KEY nametype %s", nametype); + } else if (strcasecmp(nametype, "other") != 0) /* DNSKEY */ + fatal("invalid DNSKEY nametype %s", nametype); + + rdclass = strtoclass(classname); + + if ((options & DST_TYPE_KEY) != 0) /* KEY / HMAC */ + flags |= signatory; + else if ((flags & DNS_KEYOWNER_ZONE) != 0) /* DNSKEY */ + flags |= ksk; + + if (protocol == -1) + protocol = DNS_KEYPROTO_DNSSEC; + else if ((options & DST_TYPE_KEY) == 0 && + protocol != DNS_KEYPROTO_DNSSEC) + fatal("invalid DNSKEY protocol: %d", protocol); + + if ((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) { + if (size > 0) + fatal("specified null key with non-zero size"); + if ((flags & DNS_KEYFLAG_SIGNATORYMASK) != 0) + fatal("specified null key with signing authority"); + } + + if ((flags & DNS_KEYFLAG_OWNERMASK) == DNS_KEYOWNER_ZONE && + (alg == DNS_KEYALG_DH || alg == DST_ALG_HMACMD5 || + alg == DST_ALG_HMACSHA1 || alg == DST_ALG_HMACSHA224 || + alg == DST_ALG_HMACSHA256 || alg == DST_ALG_HMACSHA384 || + alg == DST_ALG_HMACSHA512)) + fatal("a key with algorithm '%s' cannot be a zone key", + algname); + + dns_fixedname_init(&fname); + name = dns_fixedname_name(&fname); + isc_buffer_init(&buf, argv[isc_commandline_index], + strlen(argv[isc_commandline_index])); + isc_buffer_add(&buf, strlen(argv[isc_commandline_index])); + ret = dns_name_fromtext(name, &buf, dns_rootname, ISC_FALSE, NULL); + if (ret != ISC_R_SUCCESS) + fatal("invalid key name %s: %s", argv[isc_commandline_index], + isc_result_totext(ret)); + + switch(alg) { + case DNS_KEYALG_RSAMD5: + case DNS_KEYALG_RSASHA1: + param = rsa_exp; + break; + case DNS_KEYALG_DH: + param = generator; + break; + case DNS_KEYALG_DSA: + case DST_ALG_HMACMD5: + case DST_ALG_HMACSHA1: + case DST_ALG_HMACSHA224: + case DST_ALG_HMACSHA256: + case DST_ALG_HMACSHA384: + case DST_ALG_HMACSHA512: + param = 0; + break; + } + + if ((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) + null_key = ISC_TRUE; + + isc_buffer_init(&buf, filename, sizeof(filename) - 1); + + do { + conflict = ISC_FALSE; + oldkey = NULL; + + /* generate the key */ + ret = dst_key_generate(name, alg, size, param, flags, protocol, + rdclass, mctx, &key); + isc_entropy_stopcallbacksources(ectx); + + if (ret != ISC_R_SUCCESS) { + char namestr[DNS_NAME_FORMATSIZE]; + char algstr[ALG_FORMATSIZE]; + dns_name_format(name, namestr, sizeof(namestr)); + alg_format(alg, algstr, sizeof(algstr)); + fatal("failed to generate key %s/%s: %s\n", + namestr, algstr, isc_result_totext(ret)); + exit(-1); + } + + dst_key_setbits(key, dbits); + + /* + * Try to read a key with the same name, alg and id from disk. + * If there is one we must continue generating a new one + * unless we were asked to generate a null key, in which + * case we return failure. + */ + ret = dst_key_fromfile(name, dst_key_id(key), alg, + DST_TYPE_PRIVATE, NULL, mctx, &oldkey); + /* do not overwrite an existing key */ + if (ret == ISC_R_SUCCESS) { + dst_key_free(&oldkey); + conflict = ISC_TRUE; + if (null_key) + break; + } + if (conflict == ISC_TRUE) { + if (verbose > 0) { + isc_buffer_clear(&buf); + ret = dst_key_buildfilename(key, 0, NULL, &buf); + fprintf(stderr, + "%s: %s already exists, " + "generating a new key\n", + program, filename); + } + dst_key_free(&key); + } + + } while (conflict == ISC_TRUE); + + if (conflict) + fatal("cannot generate a null key when a key with id 0 " + "already exists"); + + ret = dst_key_tofile(key, options, NULL); + if (ret != ISC_R_SUCCESS) { + char keystr[KEY_FORMATSIZE]; + key_format(key, keystr, sizeof(keystr)); + fatal("failed to write key %s: %s\n", keystr, + isc_result_totext(ret)); + } + + isc_buffer_clear(&buf); + ret = dst_key_buildfilename(key, 0, NULL, &buf); + printf("%s\n", filename); + dst_key_free(&key); + + cleanup_logging(&log); + cleanup_entropy(&ectx); + dst_lib_destroy(); + dns_name_destroy(); + if (verbose > 10) + isc_mem_stats(mctx, stdout); + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/contrib/bind-9.5.2/bin/dnssec/dnssec-keygen.html b/contrib/bind-9.5.2/bin/dnssec/dnssec-keygen.html new file mode 100644 index 0000000000..ef20fcd310 --- /dev/null +++ b/contrib/bind-9.5.2/bin/dnssec/dnssec-keygen.html @@ -0,0 +1,232 @@ + + + + + +dnssec-keygen + + +
+
+
+

Name

+

dnssec-keygen — DNSSEC key generation tool

+
+
+

Synopsis

+

dnssec-keygen {-a algorithm} {-b keysize} {-n nametype} [-c class] [-e] [-f flag] [-g generator] [-h] [-k] [-p protocol] [-r randomdev] [-s strength] [-t type] [-v level] {name}

+
+
+

DESCRIPTION

+

dnssec-keygen + generates keys for DNSSEC (Secure DNS), as defined in RFC 2535 + and RFC 4034. It can also generate keys for use with + TSIG (Transaction Signatures), as defined in RFC 2845. +

+
+
+

OPTIONS

+
+
-a algorithm
+
+

+ Selects the cryptographic algorithm. The value of + algorithm must be one of RSAMD5 (RSA) or RSASHA1, + DSA, DH (Diffie Hellman), or HMAC-MD5. These values + are case insensitive. +

+

+ Note 1: that for DNSSEC, RSASHA1 is a mandatory to implement + algorithm, + and DSA is recommended. For TSIG, HMAC-MD5 is mandatory. +

+

+ Note 2: HMAC-MD5 and DH automatically set the -k flag. +

+
+
-b keysize
+

+ Specifies the number of bits in the key. The choice of key + size depends on the algorithm used. RSAMD5 / RSASHA1 keys must be + between + 512 and 2048 bits. Diffie Hellman keys must be between + 128 and 4096 bits. DSA keys must be between 512 and 1024 + bits and an exact multiple of 64. HMAC-MD5 keys must be + between 1 and 512 bits. +

+
-n nametype
+

+ Specifies the owner type of the key. The value of + nametype must either be ZONE (for a DNSSEC + zone key (KEY/DNSKEY)), HOST or ENTITY (for a key associated with + a host (KEY)), + USER (for a key associated with a user(KEY)) or OTHER (DNSKEY). + These values are case insensitive. Defaults to ZONE for DNSKEY + generation. +

+
-c class
+

+ Indicates that the DNS record containing the key should have + the specified class. If not specified, class IN is used. +

+
-e
+

+ If generating an RSAMD5/RSASHA1 key, use a large exponent. +

+
-f flag
+

+ Set the specified flag in the flag field of the KEY/DNSKEY record. + The only recognized flag is KSK (Key Signing Key) DNSKEY. +

+
-g generator
+

+ If generating a Diffie Hellman key, use this generator. + Allowed values are 2 and 5. If no generator + is specified, a known prime from RFC 2539 will be used + if possible; otherwise the default is 2. +

+
-h
+

+ Prints a short summary of the options and arguments to + dnssec-keygen. +

+
-k
+

+ Generate KEY records rather than DNSKEY records. +

+
-p protocol
+

+ Sets the protocol value for the generated key. The protocol + is a number between 0 and 255. The default is 3 (DNSSEC). + Other possible values for this argument are listed in + RFC 2535 and its successors. +

+
-r randomdev
+

+ Specifies the source of randomness. If the operating + system does not provide a /dev/random + or equivalent device, the default source of randomness + is keyboard input. randomdev + specifies + the name of a character device or file containing random + data to be used instead of the default. The special value + keyboard indicates that keyboard + input should be used. +

+
-s strength
+

+ Specifies the strength value of the key. The strength is + a number between 0 and 15, and currently has no defined + purpose in DNSSEC. +

+
-t type
+

+ Indicates the use of the key. type must be + one of AUTHCONF, NOAUTHCONF, NOAUTH, or NOCONF. The default + is AUTHCONF. AUTH refers to the ability to authenticate + data, and CONF the ability to encrypt data. +

+
-v level
+

+ Sets the debugging level. +

+
+
+
+

GENERATED KEYS

+

+ When dnssec-keygen completes + successfully, + it prints a string of the form Knnnn.+aaa+iiiii + to the standard output. This is an identification string for + the key it has generated. +

+
    +
  • nnnn is the key name. +

  • +
  • aaa is the numeric representation + of the + algorithm. +

  • +
  • iiiii is the key identifier (or + footprint). +

  • +
+

dnssec-keygen + creates two files, with names based + on the printed string. Knnnn.+aaa+iiiii.key + contains the public key, and + Knnnn.+aaa+iiiii.private contains the + private + key. +

+

+ The .key file contains a DNS KEY record + that + can be inserted into a zone file (directly or with a $INCLUDE + statement). +

+

+ The .private file contains + algorithm-specific + fields. For obvious security reasons, this file does not have + general read permission. +

+

+ Both .key and .private + files are generated for symmetric encryption algorithms such as + HMAC-MD5, even though the public and private key are equivalent. +

+
+
+

EXAMPLE

+

+ To generate a 768-bit DSA key for the domain + example.com, the following command would be + issued: +

+

dnssec-keygen -a DSA -b 768 -n ZONE example.com +

+

+ The command would print a string of the form: +

+

Kexample.com.+003+26160 +

+

+ In this example, dnssec-keygen creates + the files Kexample.com.+003+26160.key + and + Kexample.com.+003+26160.private. +

+
+
+

SEE ALSO

+

dnssec-signzone(8), + BIND 9 Administrator Reference Manual, + RFC 2539, + RFC 2845, + RFC 4033. +

+
+
+

AUTHOR

+

Internet Systems Consortium +

+
+
+ diff --git a/contrib/bind-9.5.2/bin/dnssec/dnssec-signzone.8 b/contrib/bind-9.5.2/bin/dnssec/dnssec-signzone.8 new file mode 100644 index 0000000000..9e01c83fcf --- /dev/null +++ b/contrib/bind-9.5.2/bin/dnssec/dnssec-signzone.8 @@ -0,0 +1,272 @@ +.\" 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 +.\" 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: dnssec-signzone.8,v 1.45.164.3 2009/07/11 01:43:27 tbox Exp $ +.\" +.hy 0 +.ad l +.\" Title: dnssec\-signzone +.\" Author: +.\" Generator: DocBook XSL Stylesheets v1.71.1 +.\" Date: June 30, 2000 +.\" Manual: BIND9 +.\" Source: BIND9 +.\" +.TH "DNSSEC\-SIGNZONE" "8" "June 30, 2000" "BIND9" "BIND9" +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.SH "NAME" +dnssec\-signzone \- DNSSEC zone signing tool +.SH "SYNOPSIS" +.HP 16 +\fBdnssec\-signzone\fR [\fB\-a\fR] [\fB\-c\ \fR\fB\fIclass\fR\fR] [\fB\-d\ \fR\fB\fIdirectory\fR\fR] [\fB\-e\ \fR\fB\fIend\-time\fR\fR] [\fB\-f\ \fR\fB\fIoutput\-file\fR\fR] [\fB\-g\fR] [\fB\-h\fR] [\fB\-k\ \fR\fB\fIkey\fR\fR] [\fB\-l\ \fR\fB\fIdomain\fR\fR] [\fB\-i\ \fR\fB\fIinterval\fR\fR] [\fB\-I\ \fR\fB\fIinput\-format\fR\fR] [\fB\-j\ \fR\fB\fIjitter\fR\fR] [\fB\-N\ \fR\fB\fIsoa\-serial\-format\fR\fR] [\fB\-o\ \fR\fB\fIorigin\fR\fR] [\fB\-O\ \fR\fB\fIoutput\-format\fR\fR] [\fB\-p\fR] [\fB\-r\ \fR\fB\fIrandomdev\fR\fR] [\fB\-s\ \fR\fB\fIstart\-time\fR\fR] [\fB\-t\fR] [\fB\-v\ \fR\fB\fIlevel\fR\fR] [\fB\-z\fR] {zonefile} [key...] +.SH "DESCRIPTION" +.PP +\fBdnssec\-signzone\fR +signs a zone. It generates NSEC and RRSIG records and produces a signed version of the zone. The security status of delegations from the signed zone (that is, whether the child zones are secure or not) is determined by the presence or absence of a +\fIkeyset\fR +file for each child zone. +.SH "OPTIONS" +.PP +\-a +.RS 4 +Verify all generated signatures. +.RE +.PP +\-c \fIclass\fR +.RS 4 +Specifies the DNS class of the zone. +.RE +.PP +\-k \fIkey\fR +.RS 4 +Treat specified key as a key signing key ignoring any key flags. This option may be specified multiple times. +.RE +.PP +\-l \fIdomain\fR +.RS 4 +Generate a DLV set in addition to the key (DNSKEY) and DS sets. The domain is appended to the name of the records. +.RE +.PP +\-d \fIdirectory\fR +.RS 4 +Look for +\fIkeyset\fR +files in +\fBdirectory\fR +as the directory +.RE +.PP +\-g +.RS 4 +Generate DS records for child zones from keyset files. Existing DS records will be removed. +.RE +.PP +\-s \fIstart\-time\fR +.RS 4 +Specify the date and time when the generated RRSIG records become valid. This can be either an absolute or relative time. An absolute start time is indicated by a number in YYYYMMDDHHMMSS notation; 20000530144500 denotes 14:45:00 UTC on May 30th, 2000. A relative start time is indicated by +N, which is N seconds from the current time. If no +\fBstart\-time\fR +is specified, the current time minus 1 hour (to allow for clock skew) is used. +.RE +.PP +\-e \fIend\-time\fR +.RS 4 +Specify the date and time when the generated RRSIG records expire. As with +\fBstart\-time\fR, an absolute time is indicated in YYYYMMDDHHMMSS notation. A time relative to the start time is indicated with +N, which is N seconds from the start time. A time relative to the current time is indicated with now+N. If no +\fBend\-time\fR +is specified, 30 days from the start time is used as a default. +.RE +.PP +\-f \fIoutput\-file\fR +.RS 4 +The name of the output file containing the signed zone. The default is to append +\fI.signed\fR +to the input filename. +.RE +.PP +\-h +.RS 4 +Prints a short summary of the options and arguments to +\fBdnssec\-signzone\fR. +.RE +.PP +\-i \fIinterval\fR +.RS 4 +When a previously\-signed zone is passed as input, records may be resigned. The +\fBinterval\fR +option specifies the cycle interval as an offset from the current time (in seconds). If a RRSIG record expires after the cycle interval, it is retained. Otherwise, it is considered to be expiring soon, and it will be replaced. +.sp +The default cycle interval is one quarter of the difference between the signature end and start times. So if neither +\fBend\-time\fR +or +\fBstart\-time\fR +are specified, +\fBdnssec\-signzone\fR +generates signatures that are valid for 30 days, with a cycle interval of 7.5 days. Therefore, if any existing RRSIG records are due to expire in less than 7.5 days, they would be replaced. +.RE +.PP +\-I \fIinput\-format\fR +.RS 4 +The format of the input zone file. Possible formats are +\fB"text"\fR +(default) and +\fB"raw"\fR. This option is primarily intended to be used for dynamic signed zones so that the dumped zone file in a non\-text format containing updates can be signed directly. The use of this option does not make much sense for non\-dynamic zones. +.RE +.PP +\-j \fIjitter\fR +.RS 4 +When signing a zone with a fixed signature lifetime, all RRSIG records issued at the time of signing expires simultaneously. If the zone is incrementally signed, i.e. a previously\-signed zone is passed as input to the signer, all expired signatures have to be regenerated at about the same time. The +\fBjitter\fR +option specifies a jitter window that will be used to randomize the signature expire time, thus spreading incremental signature regeneration over time. +.sp +Signature lifetime jitter also to some extent benefits validators and servers by spreading out cache expiration, i.e. if large numbers of RRSIGs don't expire at the same time from all caches there will be less congestion than if all validators need to refetch at mostly the same time. +.RE +.PP +\-n \fIncpus\fR +.RS 4 +Specifies the number of threads to use. By default, one thread is started for each detected CPU. +.RE +.PP +\-N \fIsoa\-serial\-format\fR +.RS 4 +The SOA serial number format of the signed zone. Possible formats are +\fB"keep"\fR +(default), +\fB"increment"\fR +and +\fB"unixtime"\fR. +.RS 4 +.PP +\fB"keep"\fR +.RS 4 +Do not modify the SOA serial number. +.RE +.PP +\fB"increment"\fR +.RS 4 +Increment the SOA serial number using RFC 1982 arithmetics. +.RE +.PP +\fB"unixtime"\fR +.RS 4 +Set the SOA serial number to the number of seconds since epoch. +.RE +.RE +.RE +.PP +\-o \fIorigin\fR +.RS 4 +The zone origin. If not specified, the name of the zone file is assumed to be the origin. +.RE +.PP +\-O \fIoutput\-format\fR +.RS 4 +The format of the output file containing the signed zone. Possible formats are +\fB"text"\fR +(default) and +\fB"raw"\fR. +.RE +.PP +\-p +.RS 4 +Use pseudo\-random data when signing the zone. This is faster, but less secure, than using real random data. This option may be useful when signing large zones or when the entropy source is limited. +.RE +.PP +\-r \fIrandomdev\fR +.RS 4 +Specifies the source of randomness. If the operating system does not provide a +\fI/dev/random\fR +or equivalent device, the default source of randomness is keyboard input. +\fIrandomdev\fR +specifies the name of a character device or file containing random data to be used instead of the default. The special value +\fIkeyboard\fR +indicates that keyboard input should be used. +.RE +.PP +\-t +.RS 4 +Print statistics at completion. +.RE +.PP +\-v \fIlevel\fR +.RS 4 +Sets the debugging level. +.RE +.PP +\-z +.RS 4 +Ignore KSK flag on key when determining what to sign. +.RE +.PP +zonefile +.RS 4 +The file containing the zone to be signed. +.RE +.PP +key +.RS 4 +Specify which keys should be used to sign the zone. If no keys are specified, then the zone will be examined for DNSKEY records at the zone apex. If these are found and there are matching private keys, in the current directory, then these will be used for signing. +.RE +.SH "EXAMPLE" +.PP +The following command signs the +\fBexample.com\fR +zone with the DSA key generated by +\fBdnssec\-keygen\fR +(Kexample.com.+003+17247). The zone's keys must be in the master file (\fIdb.example.com\fR). This invocation looks for +\fIkeyset\fR +files, in the current directory, so that DS records can be generated from them (\fB\-g\fR). +.sp +.RS 4 +.nf +% dnssec\-signzone \-g \-o example.com db.example.com \\ +Kexample.com.+003+17247 +db.example.com.signed +% +.fi +.RE +.PP +In the above example, +\fBdnssec\-signzone\fR +creates the file +\fIdb.example.com.signed\fR. This file should be referenced in a zone statement in a +\fInamed.conf\fR +file. +.PP +This example re\-signs a previously signed zone with default parameters. The private keys are assumed to be in the current directory. +.sp +.RS 4 +.nf +% cp db.example.com.signed db.example.com +% dnssec\-signzone \-o example.com db.example.com +db.example.com.signed +% +.fi +.RE +.SH "SEE ALSO" +.PP +\fBdnssec\-keygen\fR(8), +BIND 9 Administrator Reference Manual, +RFC 4033. +.SH "AUTHOR" +.PP +Internet Systems Consortium +.SH "COPYRIGHT" +Copyright \(co 2004\-2008 Internet Systems Consortium, Inc. ("ISC") +.br +Copyright \(co 2000\-2003 Internet Software Consortium. +.br diff --git a/contrib/bind-9.5.2/bin/dnssec/dnssec-signzone.c b/contrib/bind-9.5.2/bin/dnssec/dnssec-signzone.c new file mode 100644 index 0000000000..685033d2f6 --- /dev/null +++ b/contrib/bind-9.5.2/bin/dnssec/dnssec-signzone.c @@ -0,0 +1,2357 @@ +/* + * Portions Copyright (C) 2004-2009 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 + * 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 AND NETWORK ASSOCIATES 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. + * + * Portions Copyright (C) 1995-2000 by Network Associates, Inc. + * + * 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 AND NETWORK ASSOCIATES 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: dnssec-signzone.c,v 1.204.94.5 2009/07/21 06:45:06 tbox Exp $ */ + +/*! \file */ + +#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 +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "dnssectool.h" + +const char *program = "dnssec-signzone"; +int verbose; + +#define BUFSIZE 2048 +#define MAXDSKEYS 8 + +typedef struct signer_key_struct signer_key_t; + +struct signer_key_struct { + dst_key_t *key; + isc_boolean_t issigningkey; + isc_boolean_t isdsk; + isc_boolean_t isksk; + unsigned int position; + ISC_LINK(signer_key_t) link; +}; + +#define SIGNER_EVENTCLASS ISC_EVENTCLASS(0x4453) +#define SIGNER_EVENT_WRITE (SIGNER_EVENTCLASS + 0) +#define SIGNER_EVENT_WORK (SIGNER_EVENTCLASS + 1) + +#define SOA_SERIAL_KEEP 0 +#define SOA_SERIAL_INCREMENT 1 +#define SOA_SERIAL_UNIXTIME 2 + +typedef struct signer_event sevent_t; +struct signer_event { + ISC_EVENT_COMMON(sevent_t); + dns_fixedname_t *fname; + dns_dbnode_t *node; +}; + +static ISC_LIST(signer_key_t) keylist; +static unsigned int keycount = 0; +static isc_stdtime_t starttime = 0, endtime = 0, now; +static int cycle = -1; +static int jitter = 0; +static isc_boolean_t tryverify = ISC_FALSE; +static isc_boolean_t printstats = ISC_FALSE; +static isc_mem_t *mctx = NULL; +static isc_entropy_t *ectx = NULL; +static dns_ttl_t zonettl; +static FILE *fp; +static char *tempfile = NULL; +static const dns_master_style_t *masterstyle; +static dns_masterformat_t inputformat = dns_masterformat_text; +static dns_masterformat_t outputformat = dns_masterformat_text; +static unsigned int nsigned = 0, nretained = 0, ndropped = 0; +static unsigned int nverified = 0, nverifyfailed = 0; +static const char *directory; +static isc_mutex_t namelock, statslock; +static isc_taskmgr_t *taskmgr = NULL; +static dns_db_t *gdb; /* The database */ +static dns_dbversion_t *gversion; /* The database version */ +static dns_dbiterator_t *gdbiter; /* The database iterator */ +static dns_rdataclass_t gclass; /* The class */ +static dns_name_t *gorigin; /* The database origin */ +static isc_task_t *master = NULL; +static unsigned int ntasks = 0; +static isc_boolean_t shuttingdown = ISC_FALSE, finished = ISC_FALSE; +static isc_boolean_t nokeys = ISC_FALSE; +static isc_boolean_t removefile = ISC_FALSE; +static isc_boolean_t generateds = ISC_FALSE; +static isc_boolean_t ignoreksk = ISC_FALSE; +static dns_name_t *dlv = NULL; +static dns_fixedname_t dlv_fixed; +static dns_master_style_t *dsstyle = NULL; +static unsigned int serialformat = SOA_SERIAL_KEEP; + +#define INCSTAT(counter) \ + if (printstats) { \ + LOCK(&statslock); \ + counter++; \ + UNLOCK(&statslock); \ + } + +static void +sign(isc_task_t *task, isc_event_t *event); + + +static inline void +set_bit(unsigned char *array, unsigned int index, unsigned int bit) { + unsigned int shift, mask; + + shift = 7 - (index % 8); + mask = 1 << shift; + + if (bit != 0) + array[index / 8] |= mask; + else + array[index / 8] &= (~mask & 0xFF); +} + +static void +dumpnode(dns_name_t *name, dns_dbnode_t *node) { + isc_result_t result; + + if (outputformat != dns_masterformat_text) + return; + result = dns_master_dumpnodetostream(mctx, gdb, gversion, node, name, + masterstyle, fp); + check_result(result, "dns_master_dumpnodetostream"); +} + +static signer_key_t * +newkeystruct(dst_key_t *dstkey, isc_boolean_t signwithkey) { + signer_key_t *key; + + key = isc_mem_get(mctx, sizeof(signer_key_t)); + if (key == NULL) + fatal("out of memory"); + key->key = dstkey; + if ((dst_key_flags(dstkey) & DNS_KEYFLAG_KSK) != 0) { + key->issigningkey = signwithkey; + key->isksk = ISC_TRUE; + key->isdsk = ISC_FALSE; + } else { + key->issigningkey = signwithkey; + key->isksk = ISC_FALSE; + key->isdsk = ISC_TRUE; + } + key->position = keycount++; + ISC_LINK_INIT(key, link); + return (key); +} + +/*% + * Sign the given RRset with given key, and add the signature record to the + * given tuple. + */ + +static void +signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dst_key_t *key, + dns_ttl_t ttl, dns_diff_t *add, const char *logmsg) +{ + isc_result_t result; + isc_stdtime_t jendtime; + char keystr[KEY_FORMATSIZE]; + dns_rdata_t trdata = DNS_RDATA_INIT; + unsigned char array[BUFSIZE]; + isc_buffer_t b; + dns_difftuple_t *tuple; + + key_format(key, keystr, sizeof(keystr)); + vbprintf(1, "\t%s %s\n", logmsg, keystr); + + jendtime = (jitter != 0) ? isc_random_jitter(endtime, jitter) : endtime; + isc_buffer_init(&b, array, sizeof(array)); + result = dns_dnssec_sign(name, rdataset, key, &starttime, &jendtime, + mctx, &b, &trdata); + isc_entropy_stopcallbacksources(ectx); + if (result != ISC_R_SUCCESS) { + char keystr[KEY_FORMATSIZE]; + key_format(key, keystr, sizeof(keystr)); + fatal("dnskey '%s' failed to sign data: %s", + keystr, isc_result_totext(result)); + } + INCSTAT(nsigned); + + if (tryverify) { + result = dns_dnssec_verify(name, rdataset, key, + ISC_TRUE, mctx, &trdata); + if (result == ISC_R_SUCCESS) { + vbprintf(3, "\tsignature verified\n"); + INCSTAT(nverified); + } else { + vbprintf(3, "\tsignature failed to verify\n"); + INCSTAT(nverifyfailed); + } + } + + tuple = NULL; + result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name, ttl, &trdata, + &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(add, &tuple); +} + +static inline isc_boolean_t +issigningkey(signer_key_t *key) { + return (key->issigningkey); +} + +static inline isc_boolean_t +iszonekey(signer_key_t *key) { + return (ISC_TF(dns_name_equal(dst_key_name(key->key), gorigin) && + dst_key_iszonekey(key->key))); +} + +/*% + * Finds the key that generated a RRSIG, if possible. First look at the keys + * that we've loaded already, and then see if there's a key on disk. + */ +static signer_key_t * +keythatsigned(dns_rdata_rrsig_t *rrsig) { + isc_result_t result; + dst_key_t *pubkey = NULL, *privkey = NULL; + signer_key_t *key; + + key = ISC_LIST_HEAD(keylist); + while (key != NULL) { + if (rrsig->keyid == dst_key_id(key->key) && + rrsig->algorithm == dst_key_alg(key->key) && + dns_name_equal(&rrsig->signer, dst_key_name(key->key))) + return key; + key = ISC_LIST_NEXT(key, link); + } + + result = dst_key_fromfile(&rrsig->signer, rrsig->keyid, + rrsig->algorithm, DST_TYPE_PUBLIC, + NULL, mctx, &pubkey); + if (result != ISC_R_SUCCESS) + return (NULL); + + result = dst_key_fromfile(&rrsig->signer, rrsig->keyid, + rrsig->algorithm, + DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, + NULL, mctx, &privkey); + if (result == ISC_R_SUCCESS) { + dst_key_free(&pubkey); + key = newkeystruct(privkey, ISC_FALSE); + } else + key = newkeystruct(pubkey, ISC_FALSE); + ISC_LIST_APPEND(keylist, key, link); + return (key); +} + +/*% + * Check to see if we expect to find a key at this name. If we see a RRSIG + * and can't find the signing key that we expect to find, we drop the rrsig. + * I'm not sure if this is completely correct, but it seems to work. + */ +static isc_boolean_t +expecttofindkey(dns_name_t *name) { + unsigned int options = DNS_DBFIND_NOWILD; + dns_fixedname_t fname; + isc_result_t result; + char namestr[DNS_NAME_FORMATSIZE]; + + dns_fixedname_init(&fname); + result = dns_db_find(gdb, name, gversion, dns_rdatatype_dnskey, options, + 0, NULL, dns_fixedname_name(&fname), NULL, NULL); + switch (result) { + case ISC_R_SUCCESS: + case DNS_R_NXDOMAIN: + case DNS_R_NXRRSET: + return (ISC_TRUE); + case DNS_R_DELEGATION: + case DNS_R_CNAME: + case DNS_R_DNAME: + return (ISC_FALSE); + } + dns_name_format(name, namestr, sizeof(namestr)); + fatal("failure looking for '%s DNSKEY' in database: %s", + namestr, isc_result_totext(result)); + return (ISC_FALSE); /* removes a warning */ +} + +static inline isc_boolean_t +setverifies(dns_name_t *name, dns_rdataset_t *set, signer_key_t *key, + dns_rdata_t *rrsig) +{ + isc_result_t result; + result = dns_dnssec_verify(name, set, key->key, ISC_FALSE, mctx, rrsig); + if (result == ISC_R_SUCCESS) { + INCSTAT(nverified); + return (ISC_TRUE); + } else { + INCSTAT(nverifyfailed); + return (ISC_FALSE); + } +} + +/*% + * Signs a set. Goes through contortions to decide if each RRSIG should + * be dropped or retained, and then determines if any new SIGs need to + * be generated. + */ +static void +signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name, + dns_rdataset_t *set) +{ + dns_rdataset_t sigset; + dns_rdata_t sigrdata = DNS_RDATA_INIT; + dns_rdata_rrsig_t rrsig; + signer_key_t *key; + isc_result_t result; + isc_boolean_t nosigs = ISC_FALSE; + isc_boolean_t *wassignedby, *nowsignedby; + int arraysize; + dns_difftuple_t *tuple; + dns_ttl_t ttl; + int i; + char namestr[DNS_NAME_FORMATSIZE]; + char typestr[TYPE_FORMATSIZE]; + char sigstr[SIG_FORMATSIZE]; + + dns_name_format(name, namestr, sizeof(namestr)); + type_format(set->type, typestr, sizeof(typestr)); + + ttl = ISC_MIN(set->ttl, endtime - starttime); + + dns_rdataset_init(&sigset); + result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_rrsig, + set->type, 0, &sigset, NULL); + if (result == ISC_R_NOTFOUND) { + result = ISC_R_SUCCESS; + nosigs = ISC_TRUE; + } + if (result != ISC_R_SUCCESS) + fatal("failed while looking for '%s RRSIG %s': %s", + namestr, typestr, isc_result_totext(result)); + + vbprintf(1, "%s/%s:\n", namestr, typestr); + + arraysize = keycount; + if (!nosigs) + arraysize += dns_rdataset_count(&sigset); + wassignedby = isc_mem_get(mctx, arraysize * sizeof(isc_boolean_t)); + nowsignedby = isc_mem_get(mctx, arraysize * sizeof(isc_boolean_t)); + if (wassignedby == NULL || nowsignedby == NULL) + fatal("out of memory"); + + for (i = 0; i < arraysize; i++) + wassignedby[i] = nowsignedby[i] = ISC_FALSE; + + if (nosigs) + result = ISC_R_NOMORE; + else + result = dns_rdataset_first(&sigset); + + while (result == ISC_R_SUCCESS) { + isc_boolean_t expired, future; + isc_boolean_t keep = ISC_FALSE, resign = ISC_FALSE; + + dns_rdataset_current(&sigset, &sigrdata); + + result = dns_rdata_tostruct(&sigrdata, &rrsig, NULL); + check_result(result, "dns_rdata_tostruct"); + + future = isc_serial_lt(now, rrsig.timesigned); + + key = keythatsigned(&rrsig); + sig_format(&rrsig, sigstr, sizeof(sigstr)); + if (key != NULL && issigningkey(key)) + expired = isc_serial_gt(now + cycle, rrsig.timeexpire); + else + expired = isc_serial_gt(now, rrsig.timeexpire); + + if (isc_serial_gt(rrsig.timesigned, rrsig.timeexpire)) { + /* rrsig is dropped and not replaced */ + vbprintf(2, "\trrsig by %s dropped - " + "invalid validity period\n", + sigstr); + } else if (key == NULL && !future && + expecttofindkey(&rrsig.signer)) + { + /* rrsig is dropped and not replaced */ + vbprintf(2, "\trrsig by %s dropped - " + "private dnskey not found\n", + sigstr); + } else if (key == NULL || future) { + vbprintf(2, "\trrsig by %s %s - dnskey not found\n", + expired ? "retained" : "dropped", sigstr); + if (!expired) + keep = ISC_TRUE; + } else if (issigningkey(key)) { + if (!expired && setverifies(name, set, key, &sigrdata)) + { + vbprintf(2, "\trrsig by %s retained\n", sigstr); + keep = ISC_TRUE; + wassignedby[key->position] = ISC_TRUE; + nowsignedby[key->position] = ISC_TRUE; + } else { + vbprintf(2, "\trrsig by %s dropped - %s\n", + sigstr, + expired ? "expired" : + "failed to verify"); + wassignedby[key->position] = ISC_TRUE; + resign = ISC_TRUE; + } + } else if (iszonekey(key)) { + if (!expired && setverifies(name, set, key, &sigrdata)) + { + vbprintf(2, "\trrsig by %s retained\n", sigstr); + keep = ISC_TRUE; + wassignedby[key->position] = ISC_TRUE; + nowsignedby[key->position] = ISC_TRUE; + } else { + vbprintf(2, "\trrsig by %s dropped - %s\n", + sigstr, + expired ? "expired" : + "failed to verify"); + wassignedby[key->position] = ISC_TRUE; + } + } else if (!expired) { + vbprintf(2, "\trrsig by %s retained\n", sigstr); + keep = ISC_TRUE; + } else { + vbprintf(2, "\trrsig by %s expired\n", sigstr); + } + + if (keep) { + nowsignedby[key->position] = ISC_TRUE; + INCSTAT(nretained); + if (sigset.ttl != ttl) { + vbprintf(2, "\tfixing ttl %s\n", sigstr); + tuple = NULL; + result = dns_difftuple_create(mctx, + DNS_DIFFOP_DEL, + name, sigset.ttl, + &sigrdata, + &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(del, &tuple); + result = dns_difftuple_create(mctx, + DNS_DIFFOP_ADD, + name, ttl, + &sigrdata, + &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(add, &tuple); + } + } else { + tuple = NULL; + result = dns_difftuple_create(mctx, DNS_DIFFOP_DEL, + name, sigset.ttl, + &sigrdata, &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(del, &tuple); + INCSTAT(ndropped); + } + + if (resign) { + INSIST(!keep); + + signwithkey(name, set, key->key, ttl, add, + "resigning with dnskey"); + nowsignedby[key->position] = ISC_TRUE; + } + + dns_rdata_reset(&sigrdata); + dns_rdata_freestruct(&rrsig); + result = dns_rdataset_next(&sigset); + } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + + check_result(result, "dns_rdataset_first/next"); + if (dns_rdataset_isassociated(&sigset)) + dns_rdataset_disassociate(&sigset); + + for (key = ISC_LIST_HEAD(keylist); + key != NULL; + key = ISC_LIST_NEXT(key, link)) + { + if (nowsignedby[key->position]) + continue; + + if (!key->issigningkey) + continue; + if (!(ignoreksk || key->isdsk || + (key->isksk && + set->type == dns_rdatatype_dnskey && + dns_name_equal(name, gorigin)))) + continue; + + signwithkey(name, set, key->key, ttl, add, + "signing with dnskey"); + } + + isc_mem_put(mctx, wassignedby, arraysize * sizeof(isc_boolean_t)); + isc_mem_put(mctx, nowsignedby, arraysize * sizeof(isc_boolean_t)); +} + +static void +opendb(const char *prefix, dns_name_t *name, dns_rdataclass_t rdclass, + dns_db_t **dbp) +{ + char filename[256]; + isc_buffer_t b; + isc_result_t result; + + isc_buffer_init(&b, filename, sizeof(filename)); + if (directory != NULL) { + isc_buffer_putstr(&b, directory); + if (directory[strlen(directory) - 1] != '/') + isc_buffer_putstr(&b, "/"); + } + isc_buffer_putstr(&b, prefix); + result = dns_name_tofilenametext(name, ISC_FALSE, &b); + check_result(result, "dns_name_tofilenametext()"); + if (isc_buffer_availablelength(&b) == 0) { + char namestr[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namestr, sizeof(namestr)); + fatal("name '%s' is too long", namestr); + } + isc_buffer_putuint8(&b, 0); + + result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone, + rdclass, 0, NULL, dbp); + check_result(result, "dns_db_create()"); + + result = dns_db_load(*dbp, filename); + if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) + dns_db_detach(dbp); +} + +/*% + * Loads the key set for a child zone, if there is one, and builds DS records. + */ +static isc_result_t +loadds(dns_name_t *name, isc_uint32_t ttl, dns_rdataset_t *dsset) { + dns_db_t *db = NULL; + dns_dbversion_t *ver = NULL; + dns_dbnode_t *node = NULL; + isc_result_t result; + dns_rdataset_t keyset; + dns_rdata_t key, ds; + unsigned char dsbuf[DNS_DS_BUFFERSIZE]; + dns_diff_t diff; + dns_difftuple_t *tuple = NULL; + + opendb("keyset-", name, gclass, &db); + if (db == NULL) + return (ISC_R_NOTFOUND); + + result = dns_db_findnode(db, name, ISC_FALSE, &node); + if (result != ISC_R_SUCCESS) { + dns_db_detach(&db); + return (DNS_R_BADDB); + } + dns_rdataset_init(&keyset); + result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_dnskey, 0, 0, + &keyset, NULL); + if (result != ISC_R_SUCCESS) { + dns_db_detachnode(db, &node); + dns_db_detach(&db); + return (result); + } + + vbprintf(2, "found DNSKEY records\n"); + + result = dns_db_newversion(db, &ver); + check_result(result, "dns_db_newversion"); + + dns_diff_init(mctx, &diff); + + for (result = dns_rdataset_first(&keyset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&keyset)) + { + dns_rdata_init(&key); + dns_rdata_init(&ds); + dns_rdataset_current(&keyset, &key); + result = dns_ds_buildrdata(name, &key, DNS_DSDIGEST_SHA1, + dsbuf, &ds); + check_result(result, "dns_ds_buildrdata"); + + result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name, + ttl, &ds, &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(&diff, &tuple); + + dns_rdata_reset(&ds); + result = dns_ds_buildrdata(name, &key, DNS_DSDIGEST_SHA256, + dsbuf, &ds); + check_result(result, "dns_ds_buildrdata"); + + result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name, + ttl, &ds, &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(&diff, &tuple); + } + result = dns_diff_apply(&diff, db, ver); + check_result(result, "dns_diff_apply"); + dns_diff_clear(&diff); + + dns_db_closeversion(db, &ver, ISC_TRUE); + + result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_ds, 0, 0, + dsset, NULL); + check_result(result, "dns_db_findrdataset"); + + dns_rdataset_disassociate(&keyset); + dns_db_detachnode(db, &node); + dns_db_detach(&db); + return (result); +} + +static isc_boolean_t +nsec_setbit(dns_name_t *name, dns_rdataset_t *rdataset, dns_rdatatype_t type, + unsigned int val) +{ + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_nsec_t nsec; + unsigned int newlen; + unsigned char bitmap[8192 + 512]; + unsigned char nsecdata[8192 + 512 + DNS_NAME_MAXWIRE]; + isc_boolean_t answer = ISC_FALSE; + unsigned int i, len, window; + int octet; + + result = dns_rdataset_first(rdataset); + check_result(result, "dns_rdataset_first()"); + dns_rdataset_current(rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &nsec, NULL); + check_result(result, "dns_rdata_tostruct"); + + INSIST(nsec.len <= sizeof(bitmap)); + + newlen = 0; + + memset(bitmap, 0, sizeof(bitmap)); + for (i = 0; i < nsec.len; i += len) { + INSIST(i + 2 <= nsec.len); + window = nsec.typebits[i]; + len = nsec.typebits[i+1]; + i += 2; + INSIST(len > 0 && len <= 32); + INSIST(i + len <= nsec.len); + memmove(&bitmap[window * 32 + 512], &nsec.typebits[i], len); + } + set_bit(bitmap + 512, type, val); + for (window = 0; window < 256; window++) { + for (octet = 31; octet >= 0; octet--) + if (bitmap[window * 32 + 512 + octet] != 0) + break; + if (octet < 0) + continue; + bitmap[newlen] = window; + bitmap[newlen + 1] = octet + 1; + newlen += 2; + /* + * Overlapping move. + */ + memmove(&bitmap[newlen], &bitmap[window * 32 + 512], octet + 1); + newlen += octet + 1; + } + if (newlen != nsec.len || + memcmp(nsec.typebits, bitmap, newlen) != 0) { + dns_rdata_t newrdata = DNS_RDATA_INIT; + isc_buffer_t b; + dns_diff_t diff; + dns_difftuple_t *tuple = NULL; + + dns_diff_init(mctx, &diff); + result = dns_difftuple_create(mctx, DNS_DIFFOP_DEL, name, + rdataset->ttl, &rdata, &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(&diff, &tuple); + + nsec.typebits = bitmap; + nsec.len = newlen; + isc_buffer_init(&b, nsecdata, sizeof(nsecdata)); + result = dns_rdata_fromstruct(&newrdata, rdata.rdclass, + dns_rdatatype_nsec, &nsec, + &b); + check_result(result, "dns_rdata_fromstruct"); + + result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, + name, rdataset->ttl, + &newrdata, &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(&diff, &tuple); + result = dns_diff_apply(&diff, gdb, gversion); + check_result(result, "dns_difftuple_apply"); + dns_diff_clear(&diff); + answer = ISC_TRUE; + } + dns_rdata_freestruct(&nsec); + return (answer); +} + +static isc_boolean_t +delegation(dns_name_t *name, dns_dbnode_t *node, isc_uint32_t *ttlp) { + dns_rdataset_t nsset; + isc_result_t result; + + if (dns_name_equal(name, gorigin)) + return (ISC_FALSE); + + dns_rdataset_init(&nsset); + result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_ns, + 0, 0, &nsset, NULL); + if (dns_rdataset_isassociated(&nsset)) { + if (ttlp != NULL) + *ttlp = nsset.ttl; + dns_rdataset_disassociate(&nsset); + } + + return (ISC_TF(result == ISC_R_SUCCESS)); +} + +/*% + * Signs all records at a name. This mostly just signs each set individually, + * but also adds the RRSIG bit to any NSECs generated earlier, deals with + * parent/child KEY signatures, and handles other exceptional cases. + */ +static void +signname(dns_dbnode_t *node, dns_name_t *name) { + isc_result_t result; + dns_rdataset_t rdataset; + dns_rdatasetiter_t *rdsiter; + isc_boolean_t isdelegation = ISC_FALSE; + isc_boolean_t hasds = ISC_FALSE; + isc_boolean_t changed = ISC_FALSE; + dns_diff_t del, add; + char namestr[DNS_NAME_FORMATSIZE]; + isc_uint32_t nsttl = 0; + + dns_name_format(name, namestr, sizeof(namestr)); + + /* + * Determine if this is a delegation point. + */ + if (delegation(name, node, &nsttl)) + isdelegation = ISC_TRUE; + + /* + * If this is a delegation point, look for a DS set. + */ + if (isdelegation) { + dns_rdataset_t dsset; + dns_rdataset_t sigdsset; + + dns_rdataset_init(&dsset); + dns_rdataset_init(&sigdsset); + result = dns_db_findrdataset(gdb, node, gversion, + dns_rdatatype_ds, + 0, 0, &dsset, &sigdsset); + if (result == ISC_R_SUCCESS) { + dns_rdataset_disassociate(&dsset); + if (generateds) { + result = dns_db_deleterdataset(gdb, node, + gversion, + dns_rdatatype_ds, + 0); + check_result(result, "dns_db_deleterdataset"); + } else + hasds = ISC_TRUE; + } + if (generateds) { + result = loadds(name, nsttl, &dsset); + if (result == ISC_R_SUCCESS) { + result = dns_db_addrdataset(gdb, node, + gversion, 0, + &dsset, 0, NULL); + check_result(result, "dns_db_addrdataset"); + hasds = ISC_TRUE; + dns_rdataset_disassociate(&dsset); + if (dns_rdataset_isassociated(&sigdsset)) + dns_rdataset_disassociate(&sigdsset); + } else if (dns_rdataset_isassociated(&sigdsset)) { + result = dns_db_deleterdataset(gdb, node, + gversion, + dns_rdatatype_rrsig, + dns_rdatatype_ds); + check_result(result, "dns_db_deleterdataset"); + dns_rdataset_disassociate(&sigdsset); + } + } else if (dns_rdataset_isassociated(&sigdsset)) + dns_rdataset_disassociate(&sigdsset); + } + + /* + * Make sure that NSEC bits are appropriately set. + */ + dns_rdataset_init(&rdataset); + RUNTIME_CHECK(dns_db_findrdataset(gdb, node, gversion, + dns_rdatatype_nsec, 0, 0, &rdataset, + NULL) == ISC_R_SUCCESS); + if (!nokeys) + changed = nsec_setbit(name, &rdataset, dns_rdatatype_rrsig, 1); + if (changed) { + dns_rdataset_disassociate(&rdataset); + RUNTIME_CHECK(dns_db_findrdataset(gdb, node, gversion, + dns_rdatatype_nsec, 0, 0, + &rdataset, + NULL) == ISC_R_SUCCESS); + } + if (hasds) + (void)nsec_setbit(name, &rdataset, dns_rdatatype_ds, 1); + else + (void)nsec_setbit(name, &rdataset, dns_rdatatype_ds, 0); + dns_rdataset_disassociate(&rdataset); + + /* + * Now iterate through the rdatasets. + */ + dns_diff_init(mctx, &del); + dns_diff_init(mctx, &add); + rdsiter = NULL; + result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter); + check_result(result, "dns_db_allrdatasets()"); + result = dns_rdatasetiter_first(rdsiter); + while (result == ISC_R_SUCCESS) { + dns_rdatasetiter_current(rdsiter, &rdataset); + + /* If this is a RRSIG set, skip it. */ + if (rdataset.type == dns_rdatatype_rrsig) + goto skip; + + /* + * If this name is a delegation point, skip all records + * except NSEC and DS sets. Otherwise check that there + * isn't a DS record. + */ + if (isdelegation) { + if (rdataset.type != dns_rdatatype_nsec && + rdataset.type != dns_rdatatype_ds) + goto skip; + } else if (rdataset.type == dns_rdatatype_ds) { + char namebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namebuf, sizeof(namebuf)); + fatal("'%s': found DS RRset without NS RRset\n", + namebuf); + } + + signset(&del, &add, node, name, &rdataset); + + skip: + dns_rdataset_disassociate(&rdataset); + result = dns_rdatasetiter_next(rdsiter); + } + if (result != ISC_R_NOMORE) + fatal("rdataset iteration for name '%s' failed: %s", + namestr, isc_result_totext(result)); + + dns_rdatasetiter_destroy(&rdsiter); + + result = dns_diff_applysilently(&del, gdb, gversion); + if (result != ISC_R_SUCCESS) + fatal("failed to delete SIGs at node '%s': %s", + namestr, isc_result_totext(result)); + + result = dns_diff_applysilently(&add, gdb, gversion); + if (result != ISC_R_SUCCESS) + fatal("failed to add SIGs at node '%s': %s", + namestr, isc_result_totext(result)); + + dns_diff_clear(&del); + dns_diff_clear(&add); +} + +static inline isc_boolean_t +active_node(dns_dbnode_t *node) { + dns_rdatasetiter_t *rdsiter = NULL; + dns_rdatasetiter_t *rdsiter2 = NULL; + isc_boolean_t active = ISC_FALSE; + isc_result_t result; + dns_rdataset_t rdataset; + dns_rdatatype_t type; + dns_rdatatype_t covers; + isc_boolean_t found; + + dns_rdataset_init(&rdataset); + result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter); + check_result(result, "dns_db_allrdatasets()"); + result = dns_rdatasetiter_first(rdsiter); + while (result == ISC_R_SUCCESS) { + dns_rdatasetiter_current(rdsiter, &rdataset); + if (rdataset.type != dns_rdatatype_nsec && + rdataset.type != dns_rdatatype_rrsig) + active = ISC_TRUE; + dns_rdataset_disassociate(&rdataset); + if (!active) + result = dns_rdatasetiter_next(rdsiter); + else + result = ISC_R_NOMORE; + } + if (result != ISC_R_NOMORE) + fatal("rdataset iteration failed: %s", + isc_result_totext(result)); + + if (!active) { + /*% + * The node is empty of everything but NSEC / RRSIG records. + */ + for (result = dns_rdatasetiter_first(rdsiter); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(rdsiter)) { + dns_rdatasetiter_current(rdsiter, &rdataset); + result = dns_db_deleterdataset(gdb, node, gversion, + rdataset.type, + rdataset.covers); + check_result(result, "dns_db_deleterdataset()"); + dns_rdataset_disassociate(&rdataset); + } + if (result != ISC_R_NOMORE) + fatal("rdataset iteration failed: %s", + isc_result_totext(result)); + } else { + /* + * Delete RRSIGs for types that no longer exist. + */ + result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter2); + check_result(result, "dns_db_allrdatasets()"); + for (result = dns_rdatasetiter_first(rdsiter); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(rdsiter)) { + dns_rdatasetiter_current(rdsiter, &rdataset); + type = rdataset.type; + covers = rdataset.covers; + dns_rdataset_disassociate(&rdataset); + if (type != dns_rdatatype_rrsig) + continue; + found = ISC_FALSE; + for (result = dns_rdatasetiter_first(rdsiter2); + !found && result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(rdsiter2)) { + dns_rdatasetiter_current(rdsiter2, &rdataset); + if (rdataset.type == covers) + found = ISC_TRUE; + dns_rdataset_disassociate(&rdataset); + } + if (!found) { + if (result != ISC_R_NOMORE) + fatal("rdataset iteration failed: %s", + isc_result_totext(result)); + result = dns_db_deleterdataset(gdb, node, + gversion, type, + covers); + check_result(result, + "dns_db_deleterdataset(rrsig)"); + } else if (result != ISC_R_NOMORE && + result != ISC_R_SUCCESS) + fatal("rdataset iteration failed: %s", + isc_result_totext(result)); + } + if (result != ISC_R_NOMORE) + fatal("rdataset iteration failed: %s", + isc_result_totext(result)); + dns_rdatasetiter_destroy(&rdsiter2); + } + dns_rdatasetiter_destroy(&rdsiter); + + return (active); +} + +/*% + * Extracts the TTL from the SOA. + */ +static dns_ttl_t +soattl(void) { + dns_rdataset_t soaset; + dns_fixedname_t fname; + dns_name_t *name; + isc_result_t result; + dns_ttl_t ttl; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_soa_t soa; + + dns_fixedname_init(&fname); + name = dns_fixedname_name(&fname); + dns_rdataset_init(&soaset); + result = dns_db_find(gdb, gorigin, gversion, dns_rdatatype_soa, + 0, 0, NULL, name, &soaset, NULL); + if (result != ISC_R_SUCCESS) + fatal("failed to find an SOA at the zone apex: %s", + isc_result_totext(result)); + + result = dns_rdataset_first(&soaset); + check_result(result, "dns_rdataset_first"); + dns_rdataset_current(&soaset, &rdata); + result = dns_rdata_tostruct(&rdata, &soa, NULL); + check_result(result, "dns_rdata_tostruct"); + ttl = soa.minimum; + dns_rdataset_disassociate(&soaset); + return (ttl); +} + +/*% + * Increment (or set if nonzero) the SOA serial + */ +static isc_result_t +setsoaserial(isc_uint32_t serial) { + isc_result_t result; + dns_dbnode_t *node = NULL; + dns_rdataset_t rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_uint32_t old_serial, new_serial; + + result = dns_db_getoriginnode(gdb, &node); + if (result != ISC_R_SUCCESS) + return result; + + dns_rdataset_init(&rdataset); + + result = dns_db_findrdataset(gdb, node, gversion, + dns_rdatatype_soa, 0, + 0, &rdataset, NULL); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = dns_rdataset_first(&rdataset); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + dns_rdataset_current(&rdataset, &rdata); + + old_serial = dns_soa_getserial(&rdata); + + if (serial) { + /* Set SOA serial to the value provided. */ + new_serial = serial; + } else { + /* Increment SOA serial using RFC 1982 arithmetics */ + new_serial = (old_serial + 1) & 0xFFFFFFFF; + if (new_serial == 0) + new_serial = 1; + } + + /* If the new serial is not likely to cause a zone transfer + * (a/ixfr) from servers having the old serial, warn the user. + * + * RFC1982 section 7 defines the maximum increment to be + * (2^(32-1))-1. Using u_int32_t arithmetic, we can do a single + * comparison. (5 - 6 == (2^32)-1, not negative-one) + */ + if (new_serial == old_serial || + (new_serial - old_serial) > 0x7fffffffU) + fprintf(stderr, "%s: warning: Serial number not advanced, " + "zone may not transfer\n", program); + + dns_soa_setserial(new_serial, &rdata); + + result = dns_db_deleterdataset(gdb, node, gversion, + dns_rdatatype_soa, 0); + check_result(result, "dns_db_deleterdataset"); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = dns_db_addrdataset(gdb, node, gversion, + 0, &rdataset, 0, NULL); + check_result(result, "dns_db_addrdataset"); + if (result != ISC_R_SUCCESS) + goto cleanup; + +cleanup: + dns_rdataset_disassociate(&rdataset); + if (node != NULL) + dns_db_detachnode(gdb, &node); + dns_rdata_reset(&rdata); + + return (result); +} + +/*% + * Delete any RRSIG records at a node. + */ +static void +cleannode(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node) { + dns_rdatasetiter_t *rdsiter = NULL; + dns_rdataset_t set; + isc_result_t result, dresult; + + if (outputformat != dns_masterformat_text) + return; + + dns_rdataset_init(&set); + result = dns_db_allrdatasets(db, node, version, 0, &rdsiter); + check_result(result, "dns_db_allrdatasets"); + result = dns_rdatasetiter_first(rdsiter); + while (result == ISC_R_SUCCESS) { + isc_boolean_t destroy = ISC_FALSE; + dns_rdatatype_t covers = 0; + dns_rdatasetiter_current(rdsiter, &set); + if (set.type == dns_rdatatype_rrsig) { + covers = set.covers; + destroy = ISC_TRUE; + } + dns_rdataset_disassociate(&set); + result = dns_rdatasetiter_next(rdsiter); + if (destroy) { + dresult = dns_db_deleterdataset(db, node, version, + dns_rdatatype_rrsig, + covers); + check_result(dresult, "dns_db_deleterdataset"); + } + } + if (result != ISC_R_NOMORE) + fatal("rdataset iteration failed: %s", + isc_result_totext(result)); + dns_rdatasetiter_destroy(&rdsiter); +} + +/*% + * Set up the iterator and global state before starting the tasks. + */ +static void +presign(void) { + isc_result_t result; + + gdbiter = NULL; + result = dns_db_createiterator(gdb, ISC_FALSE, &gdbiter); + check_result(result, "dns_db_createiterator()"); + + result = dns_dbiterator_first(gdbiter); + check_result(result, "dns_dbiterator_first()"); +} + +/*% + * Clean up the iterator and global state after the tasks complete. + */ +static void +postsign(void) { + dns_dbiterator_destroy(&gdbiter); +} + +/*% + * Sign the apex of the zone. + */ +static void +signapex(void) { + dns_dbnode_t *node = NULL; + dns_fixedname_t fixed; + dns_name_t *name; + isc_result_t result; + + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + result = dns_dbiterator_current(gdbiter, &node, name); + check_result(result, "dns_dbiterator_current()"); + signname(node, name); + dumpnode(name, node); + cleannode(gdb, gversion, node); + dns_db_detachnode(gdb, &node); + result = dns_dbiterator_next(gdbiter); + if (result == ISC_R_NOMORE) + finished = ISC_TRUE; + else if (result != ISC_R_SUCCESS) + fatal("failure iterating database: %s", + isc_result_totext(result)); +} + +/*% + * Assigns a node to a worker thread. This is protected by the master task's + * lock. + */ +static void +assignwork(isc_task_t *task, isc_task_t *worker) { + dns_fixedname_t *fname; + dns_name_t *name; + dns_dbnode_t *node; + sevent_t *sevent; + dns_rdataset_t nsec; + isc_boolean_t found; + isc_result_t result; + static unsigned int ended = 0; /* Protected by namelock. */ + + if (shuttingdown) + return; + + LOCK(&namelock); + if (finished) { + ended++; + if (ended == ntasks) { + isc_task_detach(&task); + isc_app_shutdown(); + } + goto unlock; + } + + fname = isc_mem_get(mctx, sizeof(dns_fixedname_t)); + if (fname == NULL) + fatal("out of memory"); + dns_fixedname_init(fname); + name = dns_fixedname_name(fname); + node = NULL; + found = ISC_FALSE; + while (!found) { + result = dns_dbiterator_current(gdbiter, &node, name); + if (result != ISC_R_SUCCESS) + fatal("failure iterating database: %s", + isc_result_totext(result)); + dns_rdataset_init(&nsec); + result = dns_db_findrdataset(gdb, node, gversion, + dns_rdatatype_nsec, 0, 0, + &nsec, NULL); + if (result == ISC_R_SUCCESS) + found = ISC_TRUE; + else + dumpnode(name, node); + if (dns_rdataset_isassociated(&nsec)) + dns_rdataset_disassociate(&nsec); + if (!found) + dns_db_detachnode(gdb, &node); + + result = dns_dbiterator_next(gdbiter); + if (result == ISC_R_NOMORE) { + finished = ISC_TRUE; + break; + } else if (result != ISC_R_SUCCESS) + fatal("failure iterating database: %s", + isc_result_totext(result)); + } + if (!found) { + ended++; + if (ended == ntasks) { + isc_task_detach(&task); + isc_app_shutdown(); + } + isc_mem_put(mctx, fname, sizeof(dns_fixedname_t)); + goto unlock; + } + sevent = (sevent_t *) + isc_event_allocate(mctx, task, SIGNER_EVENT_WORK, + sign, NULL, sizeof(sevent_t)); + if (sevent == NULL) + fatal("failed to allocate event\n"); + + sevent->node = node; + sevent->fname = fname; + isc_task_send(worker, ISC_EVENT_PTR(&sevent)); + unlock: + UNLOCK(&namelock); +} + +/*% + * Start a worker task + */ +static void +startworker(isc_task_t *task, isc_event_t *event) { + isc_task_t *worker; + + worker = (isc_task_t *)event->ev_arg; + assignwork(task, worker); + isc_event_free(&event); +} + +/*% + * Write a node to the output file, and restart the worker task. + */ +static void +writenode(isc_task_t *task, isc_event_t *event) { + isc_task_t *worker; + sevent_t *sevent = (sevent_t *)event; + + worker = (isc_task_t *)event->ev_sender; + dumpnode(dns_fixedname_name(sevent->fname), sevent->node); + cleannode(gdb, gversion, sevent->node); + dns_db_detachnode(gdb, &sevent->node); + isc_mem_put(mctx, sevent->fname, sizeof(dns_fixedname_t)); + assignwork(task, worker); + isc_event_free(&event); +} + +/*% + * Sign a database node. + */ +static void +sign(isc_task_t *task, isc_event_t *event) { + dns_fixedname_t *fname; + dns_dbnode_t *node; + sevent_t *sevent, *wevent; + + sevent = (sevent_t *)event; + node = sevent->node; + fname = sevent->fname; + isc_event_free(&event); + + signname(node, dns_fixedname_name(fname)); + wevent = (sevent_t *) + isc_event_allocate(mctx, task, SIGNER_EVENT_WRITE, + writenode, NULL, sizeof(sevent_t)); + if (wevent == NULL) + fatal("failed to allocate event\n"); + wevent->node = node; + wevent->fname = fname; + isc_task_send(master, ISC_EVENT_PTR(&wevent)); +} + +/*% + * Generate NSEC records for the zone. + */ +static void +nsecify(void) { + dns_dbiterator_t *dbiter = NULL; + dns_dbnode_t *node = NULL, *nextnode = NULL; + dns_fixedname_t fname, fnextname, fzonecut; + dns_name_t *name, *nextname, *zonecut; + isc_boolean_t done = ISC_FALSE; + isc_result_t result; + + dns_fixedname_init(&fname); + name = dns_fixedname_name(&fname); + dns_fixedname_init(&fnextname); + nextname = dns_fixedname_name(&fnextname); + dns_fixedname_init(&fzonecut); + zonecut = NULL; + + result = dns_db_createiterator(gdb, ISC_FALSE, &dbiter); + check_result(result, "dns_db_createiterator()"); + + result = dns_dbiterator_first(dbiter); + check_result(result, "dns_dbiterator_first()"); + + while (!done) { + dns_dbiterator_current(dbiter, &node, name); + if (delegation(name, node, NULL)) { + zonecut = dns_fixedname_name(&fzonecut); + dns_name_copy(name, zonecut, NULL); + } + result = dns_dbiterator_next(dbiter); + nextnode = NULL; + while (result == ISC_R_SUCCESS) { + isc_boolean_t active = ISC_FALSE; + result = dns_dbiterator_current(dbiter, &nextnode, + nextname); + if (result != ISC_R_SUCCESS) + break; + active = active_node(nextnode); + if (!active) { + dns_db_detachnode(gdb, &nextnode); + result = dns_dbiterator_next(dbiter); + continue; + } + if (!dns_name_issubdomain(nextname, gorigin) || + (zonecut != NULL && + dns_name_issubdomain(nextname, zonecut))) + { + dns_db_detachnode(gdb, &nextnode); + result = dns_dbiterator_next(dbiter); + continue; + } + dns_db_detachnode(gdb, &nextnode); + break; + } + if (result == ISC_R_NOMORE) { + dns_name_clone(gorigin, nextname); + done = ISC_TRUE; + } else if (result != ISC_R_SUCCESS) + fatal("iterating through the database failed: %s", + isc_result_totext(result)); + result = dns_nsec_build(gdb, gversion, node, nextname, + zonettl); + check_result(result, "dns_nsec_build()"); + dns_db_detachnode(gdb, &node); + } + + dns_dbiterator_destroy(&dbiter); +} + +/*% + * Load the zone file from disk + */ +static void +loadzone(char *file, char *origin, dns_rdataclass_t rdclass, dns_db_t **db) { + isc_buffer_t b; + int len; + dns_fixedname_t fname; + dns_name_t *name; + isc_result_t result; + + len = strlen(origin); + isc_buffer_init(&b, origin, len); + isc_buffer_add(&b, len); + + dns_fixedname_init(&fname); + name = dns_fixedname_name(&fname); + result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL); + if (result != ISC_R_SUCCESS) + fatal("failed converting name '%s' to dns format: %s", + origin, isc_result_totext(result)); + + result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone, + rdclass, 0, NULL, db); + check_result(result, "dns_db_create()"); + + result = dns_db_load2(*db, file, inputformat); + if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) + fatal("failed loading zone from '%s': %s", + file, isc_result_totext(result)); +} + +/*% + * Finds all public zone keys in the zone, and attempts to load the + * private keys from disk. + */ +static void +loadzonekeys(dns_db_t *db) { + dns_dbnode_t *node; + dns_dbversion_t *currentversion; + isc_result_t result; + dst_key_t *keys[20]; + unsigned int nkeys, i; + + currentversion = NULL; + dns_db_currentversion(db, ¤tversion); + + node = NULL; + result = dns_db_findnode(db, gorigin, ISC_FALSE, &node); + if (result != ISC_R_SUCCESS) + fatal("failed to find the zone's origin: %s", + isc_result_totext(result)); + + result = dns_dnssec_findzonekeys(db, currentversion, node, gorigin, + mctx, 20, keys, &nkeys); + if (result == ISC_R_NOTFOUND) + result = ISC_R_SUCCESS; + if (result != ISC_R_SUCCESS) + fatal("failed to find the zone keys: %s", + isc_result_totext(result)); + + for (i = 0; i < nkeys; i++) { + signer_key_t *key; + + key = newkeystruct(keys[i], dst_key_isprivate(keys[i])); + ISC_LIST_APPEND(keylist, key, link); + } + dns_db_detachnode(db, &node); + dns_db_closeversion(db, ¤tversion, ISC_FALSE); +} + +/*% + * Finds all public zone keys in the zone. + */ +static void +loadzonepubkeys(dns_db_t *db) { + dns_dbversion_t *currentversion = NULL; + dns_dbnode_t *node = NULL; + dns_rdataset_t rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + dst_key_t *pubkey; + signer_key_t *key; + isc_result_t result; + + dns_db_currentversion(db, ¤tversion); + + result = dns_db_findnode(db, gorigin, ISC_FALSE, &node); + if (result != ISC_R_SUCCESS) + fatal("failed to find the zone's origin: %s", + isc_result_totext(result)); + + dns_rdataset_init(&rdataset); + result = dns_db_findrdataset(db, node, currentversion, + dns_rdatatype_dnskey, 0, 0, &rdataset, NULL); + if (result != ISC_R_SUCCESS) + fatal("failed to find keys at the zone apex: %s", + isc_result_totext(result)); + result = dns_rdataset_first(&rdataset); + check_result(result, "dns_rdataset_first"); + while (result == ISC_R_SUCCESS) { + pubkey = NULL; + dns_rdata_reset(&rdata); + dns_rdataset_current(&rdataset, &rdata); + result = dns_dnssec_keyfromrdata(gorigin, &rdata, mctx, + &pubkey); + if (result != ISC_R_SUCCESS) + goto next; + if (!dst_key_iszonekey(pubkey)) { + dst_key_free(&pubkey); + goto next; + } + + key = newkeystruct(pubkey, ISC_FALSE); + ISC_LIST_APPEND(keylist, key, link); + next: + result = dns_rdataset_next(&rdataset); + } + dns_rdataset_disassociate(&rdataset); + dns_db_detachnode(db, &node); + dns_db_closeversion(db, ¤tversion, ISC_FALSE); +} + +static void +warnifallksk(dns_db_t *db) { + dns_dbversion_t *currentversion = NULL; + dns_dbnode_t *node = NULL; + dns_rdataset_t rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_result_t result; + dns_rdata_key_t key; + isc_boolean_t have_non_ksk = ISC_FALSE; + + dns_db_currentversion(db, ¤tversion); + + result = dns_db_findnode(db, gorigin, ISC_FALSE, &node); + if (result != ISC_R_SUCCESS) + fatal("failed to find the zone's origin: %s", + isc_result_totext(result)); + + dns_rdataset_init(&rdataset); + result = dns_db_findrdataset(db, node, currentversion, + dns_rdatatype_dnskey, 0, 0, &rdataset, NULL); + if (result != ISC_R_SUCCESS) + fatal("failed to find keys at the zone apex: %s", + isc_result_totext(result)); + result = dns_rdataset_first(&rdataset); + check_result(result, "dns_rdataset_first"); + while (result == ISC_R_SUCCESS) { + dns_rdata_reset(&rdata); + dns_rdataset_current(&rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &key, NULL); + check_result(result, "dns_rdata_tostruct"); + if ((key.flags & DNS_KEYFLAG_KSK) == 0) { + have_non_ksk = ISC_TRUE; + result = ISC_R_NOMORE; + } else + result = dns_rdataset_next(&rdataset); + } + dns_rdataset_disassociate(&rdataset); + dns_db_detachnode(db, &node); + dns_db_closeversion(db, ¤tversion, ISC_FALSE); + if (!have_non_ksk && !ignoreksk) + fprintf(stderr, "%s: warning: No non-KSK dnskey found. " + "Supply non-KSK dnskey or use '-z'.\n", + program); +} + +static void +writeset(const char *prefix, dns_rdatatype_t type) { + char *filename; + char namestr[DNS_NAME_FORMATSIZE]; + dns_db_t *db = NULL; + dns_dbversion_t *version = NULL; + dns_diff_t diff; + dns_difftuple_t *tuple = NULL; + dns_fixedname_t fixed; + dns_name_t *name; + dns_rdata_t rdata, ds; + isc_boolean_t have_ksk = ISC_FALSE; + isc_boolean_t have_non_ksk = ISC_FALSE; + isc_buffer_t b; + isc_buffer_t namebuf; + isc_region_t r; + isc_result_t result; + signer_key_t *key; + unsigned char dsbuf[DNS_DS_BUFFERSIZE]; + unsigned char keybuf[DST_KEY_MAXSIZE]; + unsigned int filenamelen; + const dns_master_style_t *style = + (type == dns_rdatatype_dnskey) ? masterstyle : dsstyle; + + isc_buffer_init(&namebuf, namestr, sizeof(namestr)); + result = dns_name_tofilenametext(gorigin, ISC_FALSE, &namebuf); + check_result(result, "dns_name_tofilenametext"); + isc_buffer_putuint8(&namebuf, 0); + filenamelen = strlen(prefix) + strlen(namestr); + if (directory != NULL) + filenamelen += strlen(directory) + 1; + filename = isc_mem_get(mctx, filenamelen + 1); + if (filename == NULL) + fatal("out of memory"); + if (directory != NULL) + sprintf(filename, "%s/", directory); + else + filename[0] = 0; + strcat(filename, prefix); + strcat(filename, namestr); + + dns_diff_init(mctx, &diff); + + for (key = ISC_LIST_HEAD(keylist); + key != NULL; + key = ISC_LIST_NEXT(key, link)) + if (!key->isksk) { + have_non_ksk = ISC_TRUE; + break; + } + + for (key = ISC_LIST_HEAD(keylist); + key != NULL; + key = ISC_LIST_NEXT(key, link)) + if (key->isksk) { + have_ksk = ISC_TRUE; + break; + } + + if (type == dns_rdatatype_dlv) { + dns_name_t tname; + unsigned int labels; + + dns_name_init(&tname, NULL); + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + labels = dns_name_countlabels(gorigin); + dns_name_getlabelsequence(gorigin, 0, labels - 1, &tname); + result = dns_name_concatenate(&tname, dlv, name, NULL); + check_result(result, "dns_name_concatenate"); + } else + name = gorigin; + + for (key = ISC_LIST_HEAD(keylist); + key != NULL; + key = ISC_LIST_NEXT(key, link)) + { + if (have_ksk && have_non_ksk && !key->isksk) + continue; + dns_rdata_init(&rdata); + dns_rdata_init(&ds); + isc_buffer_init(&b, keybuf, sizeof(keybuf)); + result = dst_key_todns(key->key, &b); + check_result(result, "dst_key_todns"); + isc_buffer_usedregion(&b, &r); + dns_rdata_fromregion(&rdata, gclass, dns_rdatatype_dnskey, &r); + if (type != dns_rdatatype_dnskey) { + result = dns_ds_buildrdata(gorigin, &rdata, + DNS_DSDIGEST_SHA1, + dsbuf, &ds); + check_result(result, "dns_ds_buildrdata"); + if (type == dns_rdatatype_dlv) + ds.type = dns_rdatatype_dlv; + result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, + name, 0, &ds, &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(&diff, &tuple); + + dns_rdata_reset(&ds); + result = dns_ds_buildrdata(gorigin, &rdata, + DNS_DSDIGEST_SHA256, + dsbuf, &ds); + check_result(result, "dns_ds_buildrdata"); + if (type == dns_rdatatype_dlv) + ds.type = dns_rdatatype_dlv; + result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, + name, 0, &ds, &tuple); + + } else + result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, + gorigin, zonettl, + &rdata, &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(&diff, &tuple); + } + + result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone, + gclass, 0, NULL, &db); + check_result(result, "dns_db_create"); + + result = dns_db_newversion(db, &version); + check_result(result, "dns_db_newversion"); + + result = dns_diff_apply(&diff, db, version); + check_result(result, "dns_diff_apply"); + dns_diff_clear(&diff); + + result = dns_master_dump(mctx, db, version, style, filename); + check_result(result, "dns_master_dump"); + + isc_mem_put(mctx, filename, filenamelen + 1); + + dns_db_closeversion(db, &version, ISC_FALSE); + dns_db_detach(&db); +} + +static void +print_time(FILE *fp) { + time_t currenttime; + + if (outputformat != dns_masterformat_text) + return; + + currenttime = time(NULL); + fprintf(fp, "; File written on %s", ctime(¤ttime)); +} + +static void +print_version(FILE *fp) { + if (outputformat != dns_masterformat_text) + return; + + fprintf(fp, "; dnssec_signzone version " VERSION "\n"); +} + +static void +usage(void) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\t%s [options] zonefile [keys]\n", program); + + fprintf(stderr, "\n"); + + fprintf(stderr, "Version: %s\n", VERSION); + + fprintf(stderr, "Options: (default value in parenthesis) \n"); + fprintf(stderr, "\t-c class (IN)\n"); + fprintf(stderr, "\t-d directory\n"); + fprintf(stderr, "\t\tdirectory to find keyset files (.)\n"); + fprintf(stderr, "\t-g:\t"); + fprintf(stderr, "generate DS records from keyset files\n"); + fprintf(stderr, "\t-s [YYYYMMDDHHMMSS|+offset]:\n"); + fprintf(stderr, "\t\tRRSIG start time - absolute|offset (now - 1 hour)\n"); + fprintf(stderr, "\t-e [YYYYMMDDHHMMSS|+offset|\"now\"+offset]:\n"); + fprintf(stderr, "\t\tRRSIG end time - absolute|from start|from now " + "(now + 30 days)\n"); + fprintf(stderr, "\t-i interval:\n"); + fprintf(stderr, "\t\tcycle interval - resign " + "if < interval from end ( (end-start)/4 )\n"); + fprintf(stderr, "\t-j jitter:\n"); + fprintf(stderr, "\t\trandomize signature end time up to jitter seconds\n"); + fprintf(stderr, "\t-v debuglevel (0)\n"); + fprintf(stderr, "\t-o origin:\n"); + fprintf(stderr, "\t\tzone origin (name of zonefile)\n"); + fprintf(stderr, "\t-f outfile:\n"); + fprintf(stderr, "\t\tfile the signed zone is written in " + "(zonefile + .signed)\n"); + fprintf(stderr, "\t-I format:\n"); + fprintf(stderr, "\t\tfile format of input zonefile (text)\n"); + fprintf(stderr, "\t-O format:\n"); + fprintf(stderr, "\t\tfile format of signed zone file (text)\n"); + fprintf(stderr, "\t-N format:\n"); + fprintf(stderr, "\t\tsoa serial format of signed zone file (keep)\n"); + fprintf(stderr, "\t-r randomdev:\n"); + fprintf(stderr, "\t\ta file containing random data\n"); + fprintf(stderr, "\t-a:\t"); + fprintf(stderr, "verify generated signatures\n"); + fprintf(stderr, "\t-p:\t"); + fprintf(stderr, "use pseudorandom data (faster but less secure)\n"); + fprintf(stderr, "\t-t:\t"); + fprintf(stderr, "print statistics\n"); + fprintf(stderr, "\t-n ncpus (number of cpus present)\n"); + fprintf(stderr, "\t-k key_signing_key\n"); + fprintf(stderr, "\t-l lookasidezone\n"); + fprintf(stderr, "\t-z:\t"); + fprintf(stderr, "ignore KSK flag in DNSKEYs"); + + fprintf(stderr, "\n"); + + fprintf(stderr, "Signing Keys: "); + fprintf(stderr, "(default: all zone keys that have private keys)\n"); + fprintf(stderr, "\tkeyfile (Kname+alg+tag)\n"); + exit(0); +} + +static void +removetempfile(void) { + if (removefile) + isc_file_remove(tempfile); +} + +static void +print_stats(isc_time_t *timer_start, isc_time_t *timer_finish) { + isc_uint64_t runtime_us; /* Runtime in microseconds */ + isc_uint64_t runtime_ms; /* Runtime in milliseconds */ + isc_uint64_t sig_ms; /* Signatures per millisecond */ + + runtime_us = isc_time_microdiff(timer_finish, timer_start); + + printf("Signatures generated: %10d\n", nsigned); + printf("Signatures retained: %10d\n", nretained); + printf("Signatures dropped: %10d\n", ndropped); + printf("Signatures successfully verified: %10d\n", nverified); + printf("Signatures unsuccessfully verified: %10d\n", nverifyfailed); + runtime_ms = runtime_us / 1000; + printf("Runtime in seconds: %7u.%03u\n", + (unsigned int) (runtime_ms / 1000), + (unsigned int) (runtime_ms % 1000)); + if (runtime_us > 0) { + sig_ms = ((isc_uint64_t)nsigned * 1000000000) / runtime_us; + printf("Signatures per second: %7u.%03u\n", + (unsigned int) sig_ms / 1000, + (unsigned int) sig_ms % 1000); + } +} + +int +main(int argc, char *argv[]) { + int i, ch; + char *startstr = NULL, *endstr = NULL, *classname = NULL; + char *origin = NULL, *file = NULL, *output = NULL; + char *inputformatstr = NULL, *outputformatstr = NULL; + char *serialformatstr = NULL; + char *dskeyfile[MAXDSKEYS]; + int ndskeys = 0; + char *endp; + isc_time_t timer_start, timer_finish; + signer_key_t *key; + isc_result_t result; + isc_log_t *log = NULL; + isc_boolean_t pseudorandom = ISC_FALSE; + unsigned int eflags; + isc_boolean_t free_output = ISC_FALSE; + int tempfilelen; + dns_rdataclass_t rdclass; + isc_task_t **tasks = NULL; + isc_buffer_t b; + int len; + + masterstyle = &dns_master_style_explicitttl; + + check_result(isc_app_start(), "isc_app_start"); + + result = isc_mem_create(0, 0, &mctx); + if (result != ISC_R_SUCCESS) + fatal("out of memory"); + + dns_result_register(); + + isc_commandline_errprint = ISC_FALSE; + + while ((ch = isc_commandline_parse(argc, argv, + "ac:d:e:f:ghi:I:j:k:l:n:N:o:O:pr:s:Stv:z")) + != -1) { + switch (ch) { + case 'a': + tryverify = ISC_TRUE; + break; + + case 'c': + classname = isc_commandline_argument; + break; + + case 'd': + directory = isc_commandline_argument; + break; + + case 'e': + endstr = isc_commandline_argument; + break; + + case 'f': + output = isc_commandline_argument; + break; + + case 'g': + generateds = ISC_TRUE; + break; + + case '?': + if (isc_commandline_option != '?') + fprintf(stderr, "%s: invalid argument -%c\n", + program, isc_commandline_option); + case 'h': + usage(); + break; + + default: + fprintf(stderr, "%s: unhandled option -%c\n", + program, isc_commandline_option); + exit(1); + + case 'i': + endp = NULL; + cycle = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0' || cycle < 0) + fatal("cycle period must be numeric and " + "positive"); + break; + + case 'I': + inputformatstr = isc_commandline_argument; + break; + + case 'j': + endp = NULL; + jitter = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0' || jitter < 0) + fatal("jitter must be numeric and positive"); + break; + + case 'l': + dns_fixedname_init(&dlv_fixed); + len = strlen(isc_commandline_argument); + isc_buffer_init(&b, isc_commandline_argument, len); + isc_buffer_add(&b, len); + + dns_fixedname_init(&dlv_fixed); + dlv = dns_fixedname_name(&dlv_fixed); + result = dns_name_fromtext(dlv, &b, dns_rootname, + ISC_FALSE, NULL); + check_result(result, "dns_name_fromtext(dlv)"); + break; + + case 'k': + if (ndskeys == MAXDSKEYS) + fatal("too many key-signing keys specified"); + dskeyfile[ndskeys++] = isc_commandline_argument; + break; + + case 'n': + endp = NULL; + ntasks = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0' || ntasks > ISC_INT32_MAX) + fatal("number of cpus must be numeric"); + break; + + case 'N': + serialformatstr = isc_commandline_argument; + break; + + case 'o': + origin = isc_commandline_argument; + break; + + case 'O': + outputformatstr = isc_commandline_argument; + break; + + case 'p': + pseudorandom = ISC_TRUE; + break; + + case 'r': + setup_entropy(mctx, isc_commandline_argument, &ectx); + break; + + case 's': + startstr = isc_commandline_argument; + break; + + case 'S': + /* This is intentionally undocumented */ + /* -S: simple output style */ + masterstyle = &dns_master_style_simple; + break; + + case 't': + printstats = ISC_TRUE; + break; + + case 'v': + endp = NULL; + verbose = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') + fatal("verbose level must be numeric"); + break; + + case 'z': + ignoreksk = ISC_TRUE; + break; + } + } + + if (ectx == NULL) + setup_entropy(mctx, NULL, &ectx); + eflags = ISC_ENTROPY_BLOCKING; + if (!pseudorandom) + eflags |= ISC_ENTROPY_GOODONLY; + + result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE); + if (result != ISC_R_SUCCESS) + fatal("could not create hash context"); + + result = dst_lib_init(mctx, ectx, eflags); + if (result != ISC_R_SUCCESS) + fatal("could not initialize dst"); + + isc_stdtime_get(&now); + + if (startstr != NULL) + starttime = strtotime(startstr, now, now); + else + starttime = now - 3600; /* Allow for some clock skew. */ + + if (endstr != NULL) + endtime = strtotime(endstr, now, starttime); + else + endtime = starttime + (30 * 24 * 60 * 60); + + if (cycle == -1) + cycle = (endtime - starttime) / 4; + + if (ntasks == 0) + ntasks = isc_os_ncpus(); + vbprintf(4, "using %d cpus\n", ntasks); + + rdclass = strtoclass(classname); + + setup_logging(verbose, mctx, &log); + + argc -= isc_commandline_index; + argv += isc_commandline_index; + + if (argc < 1) + usage(); + + file = argv[0]; + + argc -= 1; + argv += 1; + + if (origin == NULL) + origin = file; + + if (output == NULL) { + free_output = ISC_TRUE; + output = isc_mem_allocate(mctx, + strlen(file) + strlen(".signed") + 1); + if (output == NULL) + fatal("out of memory"); + sprintf(output, "%s.signed", file); + } + + if (inputformatstr != NULL) { + if (strcasecmp(inputformatstr, "text") == 0) + inputformat = dns_masterformat_text; + else if (strcasecmp(inputformatstr, "raw") == 0) + inputformat = dns_masterformat_raw; + else + fatal("unknown file format: %s\n", inputformatstr); + } + + if (outputformatstr != NULL) { + if (strcasecmp(outputformatstr, "text") == 0) + outputformat = dns_masterformat_text; + else if (strcasecmp(outputformatstr, "raw") == 0) + outputformat = dns_masterformat_raw; + else + fatal("unknown file format: %s\n", outputformatstr); + } + + if (serialformatstr != NULL) { + if (strcasecmp(serialformatstr, "keep") == 0) + serialformat = SOA_SERIAL_KEEP; + else if (strcasecmp(serialformatstr, "increment") == 0 || + strcasecmp(serialformatstr, "incr") == 0) + serialformat = SOA_SERIAL_INCREMENT; + else if (strcasecmp(serialformatstr, "unixtime") == 0) + serialformat = SOA_SERIAL_UNIXTIME; + else + fatal("unknown soa serial format: %s\n", serialformatstr); + } + + result = dns_master_stylecreate(&dsstyle, DNS_STYLEFLAG_NO_TTL, + 0, 24, 0, 0, 0, 8, mctx); + check_result(result, "dns_master_stylecreate"); + + + gdb = NULL; + TIME_NOW(&timer_start); + loadzone(file, origin, rdclass, &gdb); + gorigin = dns_db_origin(gdb); + gclass = dns_db_class(gdb); + zonettl = soattl(); + + ISC_LIST_INIT(keylist); + + if (argc == 0) { + loadzonekeys(gdb); + } else { + for (i = 0; i < argc; i++) { + dst_key_t *newkey = NULL; + + result = dst_key_fromnamedfile(argv[i], + DST_TYPE_PUBLIC | + DST_TYPE_PRIVATE, + mctx, &newkey); + if (result != ISC_R_SUCCESS) + fatal("cannot load dnskey %s: %s", argv[i], + isc_result_totext(result)); + + if (!dns_name_equal(gorigin, dst_key_name(newkey))) + fatal("key %s not at origin\n", argv[i]); + + key = ISC_LIST_HEAD(keylist); + while (key != NULL) { + dst_key_t *dkey = key->key; + if (dst_key_id(dkey) == dst_key_id(newkey) && + dst_key_alg(dkey) == dst_key_alg(newkey) && + dns_name_equal(dst_key_name(dkey), + dst_key_name(newkey))) + { + if (!dst_key_isprivate(dkey)) + fatal("cannot sign zone with " + "non-private dnskey %s", + argv[i]); + break; + } + key = ISC_LIST_NEXT(key, link); + } + if (key == NULL) { + key = newkeystruct(newkey, ISC_TRUE); + ISC_LIST_APPEND(keylist, key, link); + } else + dst_key_free(&newkey); + } + + loadzonepubkeys(gdb); + } + + for (i = 0; i < ndskeys; i++) { + dst_key_t *newkey = NULL; + + result = dst_key_fromnamedfile(dskeyfile[i], + DST_TYPE_PUBLIC | + DST_TYPE_PRIVATE, + mctx, &newkey); + if (result != ISC_R_SUCCESS) + fatal("cannot load dnskey %s: %s", dskeyfile[i], + isc_result_totext(result)); + + if (!dns_name_equal(gorigin, dst_key_name(newkey))) + fatal("key %s not at origin\n", dskeyfile[i]); + + key = ISC_LIST_HEAD(keylist); + while (key != NULL) { + dst_key_t *dkey = key->key; + if (dst_key_id(dkey) == dst_key_id(newkey) && + dst_key_alg(dkey) == dst_key_alg(newkey) && + dns_name_equal(dst_key_name(dkey), + dst_key_name(newkey))) + { + /* Override key flags. */ + key->issigningkey = ISC_TRUE; + key->isksk = ISC_TRUE; + key->isdsk = ISC_FALSE; + dst_key_free(&dkey); + key->key = newkey; + break; + } + key = ISC_LIST_NEXT(key, link); + } + if (key == NULL) { + /* Override dnskey flags. */ + key = newkeystruct(newkey, ISC_TRUE); + key->isksk = ISC_TRUE; + key->isdsk = ISC_FALSE; + ISC_LIST_APPEND(keylist, key, link); + } + } + + if (ISC_LIST_EMPTY(keylist)) { + fprintf(stderr, "%s: warning: No keys specified or found\n", + program); + nokeys = ISC_TRUE; + } + + warnifallksk(gdb); + + gversion = NULL; + result = dns_db_newversion(gdb, &gversion); + check_result(result, "dns_db_newversion()"); + + switch (serialformat) { + case SOA_SERIAL_INCREMENT: + setsoaserial(0); + break; + case SOA_SERIAL_UNIXTIME: + setsoaserial(now); + break; + case SOA_SERIAL_KEEP: + default: + /* do nothing */ + break; + } + + nsecify(); + + if (!nokeys) { + writeset("keyset-", dns_rdatatype_dnskey); + writeset("dsset-", dns_rdatatype_ds); + if (dlv != NULL) { + writeset("dlvset-", dns_rdatatype_dlv); + } + } + + tempfilelen = strlen(output) + 20; + tempfile = isc_mem_get(mctx, tempfilelen); + if (tempfile == NULL) + fatal("out of memory"); + + result = isc_file_mktemplate(output, tempfile, tempfilelen); + check_result(result, "isc_file_mktemplate"); + + fp = NULL; + result = isc_file_openunique(tempfile, &fp); + if (result != ISC_R_SUCCESS) + fatal("failed to open temporary output file: %s", + isc_result_totext(result)); + removefile = ISC_TRUE; + setfatalcallback(&removetempfile); + + print_time(fp); + print_version(fp); + + result = isc_taskmgr_create(mctx, ntasks, 0, &taskmgr); + if (result != ISC_R_SUCCESS) + fatal("failed to create task manager: %s", + isc_result_totext(result)); + + master = NULL; + result = isc_task_create(taskmgr, 0, &master); + if (result != ISC_R_SUCCESS) + fatal("failed to create task: %s", isc_result_totext(result)); + + tasks = isc_mem_get(mctx, ntasks * sizeof(isc_task_t *)); + if (tasks == NULL) + fatal("out of memory"); + for (i = 0; i < (int)ntasks; i++) { + tasks[i] = NULL; + result = isc_task_create(taskmgr, 0, &tasks[i]); + if (result != ISC_R_SUCCESS) + fatal("failed to create task: %s", + isc_result_totext(result)); + } + + RUNTIME_CHECK(isc_mutex_init(&namelock) == ISC_R_SUCCESS); + if (printstats) + RUNTIME_CHECK(isc_mutex_init(&statslock) == ISC_R_SUCCESS); + + presign(); + signapex(); + if (!finished) { + /* + * There is more work to do. Spread it out over multiple + * processors if possible. + */ + for (i = 0; i < (int)ntasks; i++) { + result = isc_app_onrun(mctx, master, startworker, + tasks[i]); + if (result != ISC_R_SUCCESS) + fatal("failed to start task: %s", + isc_result_totext(result)); + } + (void)isc_app_run(); + if (!finished) + fatal("process aborted by user"); + } else + isc_task_detach(&master); + shuttingdown = ISC_TRUE; + for (i = 0; i < (int)ntasks; i++) + isc_task_detach(&tasks[i]); + isc_taskmgr_destroy(&taskmgr); + isc_mem_put(mctx, tasks, ntasks * sizeof(isc_task_t *)); + postsign(); + + if (outputformat != dns_masterformat_text) { + result = dns_master_dumptostream2(mctx, gdb, gversion, + masterstyle, outputformat, + fp); + check_result(result, "dns_master_dumptostream2"); + } + + result = isc_stdio_close(fp); + check_result(result, "isc_stdio_close"); + removefile = ISC_FALSE; + + result = isc_file_rename(tempfile, output); + if (result != ISC_R_SUCCESS) + fatal("failed to rename temp file to %s: %s\n", + output, isc_result_totext(result)); + + DESTROYLOCK(&namelock); + if (printstats) + DESTROYLOCK(&statslock); + + printf("%s\n", output); + + dns_db_closeversion(gdb, &gversion, ISC_FALSE); + dns_db_detach(&gdb); + + while (!ISC_LIST_EMPTY(keylist)) { + key = ISC_LIST_HEAD(keylist); + ISC_LIST_UNLINK(keylist, key, link); + dst_key_free(&key->key); + isc_mem_put(mctx, key, sizeof(signer_key_t)); + } + + isc_mem_put(mctx, tempfile, tempfilelen); + + if (free_output) + isc_mem_free(mctx, output); + + dns_master_styledestroy(&dsstyle, mctx); + + cleanup_logging(&log); + dst_lib_destroy(); + isc_hash_destroy(); + cleanup_entropy(&ectx); + dns_name_destroy(); + if (verbose > 10) + isc_mem_stats(mctx, stdout); + isc_mem_destroy(&mctx); + + (void) isc_app_finish(); + + if (printstats) { + TIME_NOW(&timer_finish); + print_stats(&timer_start, &timer_finish); + } + + return (0); +} diff --git a/contrib/bind-9.5.2/bin/dnssec/dnssec-signzone.html b/contrib/bind-9.5.2/bin/dnssec/dnssec-signzone.html new file mode 100644 index 0000000000..6755fecdd6 --- /dev/null +++ b/contrib/bind-9.5.2/bin/dnssec/dnssec-signzone.html @@ -0,0 +1,285 @@ + + + + + +dnssec-signzone + + +
+
+
+

Name

+

dnssec-signzone — DNSSEC zone signing tool

+
+
+

Synopsis

+

dnssec-signzone [-a] [-c class] [-d directory] [-e end-time] [-f output-file] [-g] [-h] [-k key] [-l domain] [-i interval] [-I input-format] [-j jitter] [-N soa-serial-format] [-o origin] [-O output-format] [-p] [-r randomdev] [-s start-time] [-t] [-v level] [-z] {zonefile} [key...]

+
+
+

DESCRIPTION

+

dnssec-signzone + signs a zone. It generates + NSEC and RRSIG records and produces a signed version of the + zone. The security status of delegations from the signed zone + (that is, whether the child zones are secure or not) is + determined by the presence or absence of a + keyset file for each child zone. +

+
+
+

OPTIONS

+
+
-a
+

+ Verify all generated signatures. +

+
-c class
+

+ Specifies the DNS class of the zone. +

+
-k key
+

+ Treat specified key as a key signing key ignoring any + key flags. This option may be specified multiple times. +

+
-l domain
+

+ Generate a DLV set in addition to the key (DNSKEY) and DS sets. + The domain is appended to the name of the records. +

+
-d directory
+

+ Look for keyset files in + directory as the directory +

+
-g
+

+ Generate DS records for child zones from keyset files. + Existing DS records will be removed. +

+
-s start-time
+

+ Specify the date and time when the generated RRSIG records + become valid. This can be either an absolute or relative + time. An absolute start time is indicated by a number + in YYYYMMDDHHMMSS notation; 20000530144500 denotes + 14:45:00 UTC on May 30th, 2000. A relative start time is + indicated by +N, which is N seconds from the current time. + If no start-time is specified, the current + time minus 1 hour (to allow for clock skew) is used. +

+
-e end-time
+

+ Specify the date and time when the generated RRSIG records + expire. As with start-time, an absolute + time is indicated in YYYYMMDDHHMMSS notation. A time relative + to the start time is indicated with +N, which is N seconds from + the start time. A time relative to the current time is + indicated with now+N. If no end-time is + specified, 30 days from the start time is used as a default. +

+
-f output-file
+

+ The name of the output file containing the signed zone. The + default is to append .signed to + the + input filename. +

+
-h
+

+ Prints a short summary of the options and arguments to + dnssec-signzone. +

+
-i interval
+
+

+ When a previously-signed zone is passed as input, records + may be resigned. The interval option + specifies the cycle interval as an offset from the current + time (in seconds). If a RRSIG record expires after the + cycle interval, it is retained. Otherwise, it is considered + to be expiring soon, and it will be replaced. +

+

+ The default cycle interval is one quarter of the difference + between the signature end and start times. So if neither + end-time or start-time + are specified, dnssec-signzone + generates + signatures that are valid for 30 days, with a cycle + interval of 7.5 days. Therefore, if any existing RRSIG records + are due to expire in less than 7.5 days, they would be + replaced. +

+
+
-I input-format
+

+ The format of the input zone file. + Possible formats are "text" (default) + and "raw". + This option is primarily intended to be used for dynamic + signed zones so that the dumped zone file in a non-text + format containing updates can be signed directly. + The use of this option does not make much sense for + non-dynamic zones. +

+
-j jitter
+
+

+ When signing a zone with a fixed signature lifetime, all + RRSIG records issued at the time of signing expires + simultaneously. If the zone is incrementally signed, i.e. + a previously-signed zone is passed as input to the signer, + all expired signatures have to be regenerated at about the + same time. The jitter option specifies a + jitter window that will be used to randomize the signature + expire time, thus spreading incremental signature + regeneration over time. +

+

+ Signature lifetime jitter also to some extent benefits + validators and servers by spreading out cache expiration, + i.e. if large numbers of RRSIGs don't expire at the same time + from all caches there will be less congestion than if all + validators need to refetch at mostly the same time. +

+
+
-n ncpus
+

+ Specifies the number of threads to use. By default, one + thread is started for each detected CPU. +

+
-N soa-serial-format
+
+

+ The SOA serial number format of the signed zone. + Possible formats are "keep" (default), + "increment" and + "unixtime". +

+
+
"keep"
+

Do not modify the SOA serial number.

+
"increment"
+

Increment the SOA serial number using RFC 1982 + arithmetics.

+
"unixtime"
+

Set the SOA serial number to the number of seconds + since epoch.

+
+
+
-o origin
+

+ The zone origin. If not specified, the name of the zone file + is assumed to be the origin. +

+
-O output-format
+

+ The format of the output file containing the signed zone. + Possible formats are "text" (default) + and "raw". +

+
-p
+

+ Use pseudo-random data when signing the zone. This is faster, + but less secure, than using real random data. This option + may be useful when signing large zones or when the entropy + source is limited. +

+
-r randomdev
+

+ Specifies the source of randomness. If the operating + system does not provide a /dev/random + or equivalent device, the default source of randomness + is keyboard input. randomdev + specifies + the name of a character device or file containing random + data to be used instead of the default. The special value + keyboard indicates that keyboard + input should be used. +

+
-t
+

+ Print statistics at completion. +

+
-v level
+

+ Sets the debugging level. +

+
-z
+

+ Ignore KSK flag on key when determining what to sign. +

+
zonefile
+

+ The file containing the zone to be signed. +

+
key
+

+ Specify which keys should be used to sign the zone. If + no keys are specified, then the zone will be examined + for DNSKEY records at the zone apex. If these are found and + there are matching private keys, in the current directory, + then these will be used for signing. +

+
+
+
+

EXAMPLE

+

+ The following command signs the example.com + zone with the DSA key generated by dnssec-keygen + (Kexample.com.+003+17247). The zone's keys must be in the master + file (db.example.com). This invocation looks + for keyset files, in the current directory, + so that DS records can be generated from them (-g). +

+
% dnssec-signzone -g -o example.com db.example.com \
+Kexample.com.+003+17247
+db.example.com.signed
+%
+

+ In the above example, dnssec-signzone creates + the file db.example.com.signed. This + file should be referenced in a zone statement in a + named.conf file. +

+

+ This example re-signs a previously signed zone with default parameters. + The private keys are assumed to be in the current directory. +

+
% cp db.example.com.signed db.example.com
+% dnssec-signzone -o example.com db.example.com
+db.example.com.signed
+%
+
+
+

SEE ALSO

+

dnssec-keygen(8), + BIND 9 Administrator Reference Manual, + RFC 4033. +

+
+
+

AUTHOR

+

Internet Systems Consortium +

+
+
+ diff --git a/contrib/bind-9.5.2/bin/dnssec/dnssectool.c b/contrib/bind-9.5.2/bin/dnssec/dnssectool.c new file mode 100644 index 0000000000..e933a06d60 --- /dev/null +++ b/contrib/bind-9.5.2/bin/dnssec/dnssectool.c @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2004, 2005, 2007 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 + * 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: dnssectool.c,v 1.45 2007/06/19 23:46:59 tbox Exp $ */ + +/*! \file */ + +/*% + * DNSSEC Support Routines. + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dnssectool.h" + +extern int verbose; +extern const char *program; + +typedef struct entropysource entropysource_t; + +struct entropysource { + isc_entropysource_t *source; + isc_mem_t *mctx; + ISC_LINK(entropysource_t) link; +}; + +static ISC_LIST(entropysource_t) sources; +static fatalcallback_t *fatalcallback = NULL; + +void +fatal(const char *format, ...) { + va_list args; + + fprintf(stderr, "%s: ", program); + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + if (fatalcallback != NULL) + (*fatalcallback)(); + exit(1); +} + +void +setfatalcallback(fatalcallback_t *callback) { + fatalcallback = callback; +} + +void +check_result(isc_result_t result, const char *message) { + if (result != ISC_R_SUCCESS) + fatal("%s: %s", message, isc_result_totext(result)); +} + +void +vbprintf(int level, const char *fmt, ...) { + va_list ap; + if (level > verbose) + return; + va_start(ap, fmt); + fprintf(stderr, "%s: ", program); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +void +type_format(const dns_rdatatype_t type, char *cp, unsigned int size) { + isc_buffer_t b; + isc_region_t r; + isc_result_t result; + + isc_buffer_init(&b, cp, size - 1); + result = dns_rdatatype_totext(type, &b); + check_result(result, "dns_rdatatype_totext()"); + isc_buffer_usedregion(&b, &r); + r.base[r.length] = 0; +} + +void +alg_format(const dns_secalg_t alg, char *cp, unsigned int size) { + isc_buffer_t b; + isc_region_t r; + isc_result_t result; + + isc_buffer_init(&b, cp, size - 1); + result = dns_secalg_totext(alg, &b); + check_result(result, "dns_secalg_totext()"); + isc_buffer_usedregion(&b, &r); + r.base[r.length] = 0; +} + +void +sig_format(dns_rdata_rrsig_t *sig, char *cp, unsigned int size) { + char namestr[DNS_NAME_FORMATSIZE]; + char algstr[DNS_NAME_FORMATSIZE]; + + dns_name_format(&sig->signer, namestr, sizeof(namestr)); + alg_format(sig->algorithm, algstr, sizeof(algstr)); + snprintf(cp, size, "%s/%s/%d", namestr, algstr, sig->keyid); +} + +void +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)); + alg_format((dns_secalg_t) dst_key_alg(key), algstr, sizeof(algstr)); + snprintf(cp, size, "%s/%s/%d", namestr, algstr, dst_key_id(key)); +} + +void +setup_logging(int verbose, isc_mem_t *mctx, isc_log_t **logp) { + isc_result_t result; + isc_logdestination_t destination; + isc_logconfig_t *logconfig = NULL; + isc_log_t *log = NULL; + int level; + + if (verbose < 0) + verbose = 0; + switch (verbose) { + case 0: + /* + * We want to see warnings about things like out-of-zone + * data in the master file even when not verbose. + */ + level = ISC_LOG_WARNING; + break; + case 1: + level = ISC_LOG_INFO; + break; + default: + level = ISC_LOG_DEBUG(verbose - 2 + 1); + break; + } + + RUNTIME_CHECK(isc_log_create(mctx, &log, &logconfig) == ISC_R_SUCCESS); + isc_log_setcontext(log); + dns_log_init(log); + dns_log_setcontext(log); + + RUNTIME_CHECK(isc_log_settag(logconfig, program) == ISC_R_SUCCESS); + + /* + * Set up a channel similar to default_stderr except: + * - the logging level is passed in + * - the program name and logging level are printed + * - no time stamp is printed + */ + destination.file.stream = stderr; + destination.file.name = NULL; + destination.file.versions = ISC_LOG_ROLLNEVER; + destination.file.maximum_size = 0; + result = isc_log_createchannel(logconfig, "stderr", + ISC_LOG_TOFILEDESC, + level, + &destination, + ISC_LOG_PRINTTAG|ISC_LOG_PRINTLEVEL); + check_result(result, "isc_log_createchannel()"); + + RUNTIME_CHECK(isc_log_usechannel(logconfig, "stderr", + NULL, NULL) == ISC_R_SUCCESS); + + *logp = log; +} + +void +cleanup_logging(isc_log_t **logp) { + isc_log_t *log; + + REQUIRE(logp != NULL); + + log = *logp; + if (log == NULL) + return; + isc_log_destroy(&log); + isc_log_setcontext(NULL); + dns_log_setcontext(NULL); + logp = NULL; +} + +void +setup_entropy(isc_mem_t *mctx, const char *randomfile, isc_entropy_t **ectx) { + isc_result_t result; + isc_entropysource_t *source = NULL; + entropysource_t *elt; + int usekeyboard = ISC_ENTROPY_KEYBOARDMAYBE; + + REQUIRE(ectx != NULL); + + if (*ectx == NULL) { + result = isc_entropy_create(mctx, ectx); + if (result != ISC_R_SUCCESS) + fatal("could not create entropy object"); + ISC_LIST_INIT(sources); + } + + if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) { + usekeyboard = ISC_ENTROPY_KEYBOARDYES; + randomfile = NULL; + } + + result = isc_entropy_usebestsource(*ectx, &source, randomfile, + usekeyboard); + + if (result != ISC_R_SUCCESS) + fatal("could not initialize entropy source: %s", + isc_result_totext(result)); + + if (source != NULL) { + elt = isc_mem_get(mctx, sizeof(*elt)); + if (elt == NULL) + fatal("out of memory"); + elt->source = source; + elt->mctx = mctx; + ISC_LINK_INIT(elt, link); + ISC_LIST_APPEND(sources, elt, link); + } +} + +void +cleanup_entropy(isc_entropy_t **ectx) { + entropysource_t *source; + while (!ISC_LIST_EMPTY(sources)) { + source = ISC_LIST_HEAD(sources); + ISC_LIST_UNLINK(sources, source, link); + isc_entropy_destroysource(&source->source); + isc_mem_put(source->mctx, source, sizeof(*source)); + } + isc_entropy_detach(ectx); +} + +isc_stdtime_t +strtotime(const char *str, isc_int64_t now, isc_int64_t base) { + isc_int64_t val, offset; + isc_result_t result; + char *endp; + + if (str[0] == '+') { + offset = strtol(str + 1, &endp, 0); + if (*endp != '\0') + fatal("time value %s is invalid", str); + val = base + offset; + } else if (strncmp(str, "now+", 4) == 0) { + offset = strtol(str + 4, &endp, 0); + if (*endp != '\0') + fatal("time value %s is invalid", str); + val = now + offset; + } else if (strlen(str) == 8U) { + char timestr[15]; + sprintf(timestr, "%s000000", str); + result = dns_time64_fromtext(timestr, &val); + if (result != ISC_R_SUCCESS) + fatal("time value %s is invalid", str); + } else { + result = dns_time64_fromtext(str, &val); + if (result != ISC_R_SUCCESS) + fatal("time value %s is invalid", str); + } + + return ((isc_stdtime_t) val); +} + +dns_rdataclass_t +strtoclass(const char *str) { + isc_textregion_t r; + dns_rdataclass_t rdclass; + isc_result_t ret; + + if (str == NULL) + return dns_rdataclass_in; + DE_CONST(str, r.base); + r.length = strlen(str); + ret = dns_rdataclass_fromtext(&rdclass, &r); + if (ret != ISC_R_SUCCESS) + fatal("unknown class %s", str); + return (rdclass); +} diff --git a/contrib/bind-9.5.2/bin/dnssec/dnssectool.h b/contrib/bind-9.5.2/bin/dnssec/dnssectool.h new file mode 100644 index 0000000000..a0b20e37e3 --- /dev/null +++ b/contrib/bind-9.5.2/bin/dnssec/dnssectool.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2004, 2007 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 + * 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: dnssectool.h,v 1.20 2007/06/19 23:46:59 tbox Exp $ */ + +#ifndef DNSSECTOOL_H +#define DNSSECTOOL_H 1 + +#include +#include +#include +#include + +typedef void (fatalcallback_t)(void); + +void +fatal(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +void +setfatalcallback(fatalcallback_t *callback); + +void +check_result(isc_result_t result, const char *message); + +void +vbprintf(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3); + +void +type_format(const dns_rdatatype_t type, char *cp, unsigned int size); +#define TYPE_FORMATSIZE 10 + +void +alg_format(const dns_secalg_t alg, char *cp, unsigned int size); +#define ALG_FORMATSIZE 10 + +void +sig_format(dns_rdata_rrsig_t *sig, char *cp, unsigned int size); +#define SIG_FORMATSIZE (DNS_NAME_FORMATSIZE + ALG_FORMATSIZE + sizeof("65535")) + +void +key_format(const dst_key_t *key, char *cp, unsigned int size); +#define KEY_FORMATSIZE (DNS_NAME_FORMATSIZE + ALG_FORMATSIZE + sizeof("65535")) + +void +setup_logging(int verbose, isc_mem_t *mctx, isc_log_t **logp); + +void +cleanup_logging(isc_log_t **logp); + +void +setup_entropy(isc_mem_t *mctx, const char *randomfile, isc_entropy_t **ectx); + +void +cleanup_entropy(isc_entropy_t **ectx); + +isc_stdtime_t +strtotime(const char *str, isc_int64_t now, isc_int64_t base); + +dns_rdataclass_t +strtoclass(const char *str); + +#endif /* DNSSEC_DNSSECTOOL_H */ diff --git a/contrib/bind-9.5.2/bin/named/bind9.xsl b/contrib/bind-9.5.2/bin/named/bind9.xsl new file mode 100644 index 0000000000..65a50a7812 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/bind9.xsl @@ -0,0 +1,492 @@ + + + + + + + + + + + BIND 9 Statistics + + +
+

Bind 9 Configuration and Statistics

+
+ +
+ + + + + + + + + + + +
Times
boot-time
current-time
+ +
+ + + + + + + + + +
Incoming Requests
+ +
+ + + + + + + + + +
Incoming Queries
+ +
+ + + + + + + + + + + + +
Outgoing Queries from View
+
+
+ +
+ +
+

Server Statistics

+ +
+
+
+
+
+
+
+ +
+

Zone Maintenance Statistics

+ +
+
+
+
+
+
+
+ +
+

Resolver Statistics (Common)

+ +
+
+
+
+
+
+
+ + +
+

Resolver Statistics for View

+ +
+
+
+
+
+
+
+
+ +
+ + + + + + + + + + + + +
Cache DB RRsets for View
+
+
+ +
+

Socket I/O Statistics

+ +
+
+
+
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Zones for View
NameClassSerialSuccessReferralNXRRSETNXDOMAINFailureXfrReqDoneXfrRej
+ + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Network Status
IDNameTypeReferencesLocalAddressPeerAddressState
+ + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +
Task Manager Configuration
Thread-Model + +
Worker Threads + +
Default Quantum + +
Tasks Running + +
+
+ + + + + + + + + + + + + + + + + + + + +
Tasks
IDNameReferencesStateQuantum
+ + + + + + + + + +
+
+ + + + + + + + + + +
Memory Usage Summary
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Memory Contexts
IDNameReferencesTotalUseInUseMaxUseBlockSizePoolsHiWaterLoWater
+ + + + + + + + + + + + + + + + + + + +
+ + + +
+
diff --git a/contrib/bind-9.5.2/bin/named/bind9.xsl.h b/contrib/bind-9.5.2/bin/named/bind9.xsl.h new file mode 100644 index 0000000000..020c48ad27 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/bind9.xsl.h @@ -0,0 +1,497 @@ +/* + * Generated by convertxsl.pl 1.9.60.5 2008/07/17 23:50:58 jinmei Exp + * From bind9.xsl 1.13.130.8 2009/01/29 23:47:13 tbox Exp + */ +static char xslmsg[] = + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " BIND 9 Statistics\n" + " \n" + " \n" + "
\n" + "

Bind 9 Configuration and Statistics

\n" + "
\n" + "\n" + "
\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
Times
boot-time
current-time
\n" + "\n" + "
\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
Incoming Requests
\n" + "\n" + "
\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
Incoming Queries
\n" + "\n" + "
\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
Outgoing Queries from View
\n" + "
\n" + "
\n" + "\n" + "
\n" + "\n" + "
\n" + "

Server Statistics

\n" + " \n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "\n" + "
\n" + "

Zone Maintenance Statistics

\n" + " \n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "\n" + "
\n" + "

Resolver Statistics (Common)

\n" + " \n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "\n" + " \n" + "
\n" + "

Resolver Statistics for View

\n" + " \n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "\n" + "
\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
Cache DB RRsets for View
\n" + "
\n" + "
\n" + "\n" + "
\n" + "

Socket I/O Statistics

\n" + " \n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "\n" + "
\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
Zones for View
NameClassSerialSuccessReferralNXRRSETNXDOMAINFailureXfrReqDoneXfrRej
\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + "
\n" + "\n" + "
\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
Network Status
IDNameTypeReferencesLocalAddressPeerAddressState
\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
Task Manager Configuration
Thread-Model\n" + " \n" + "
Worker Threads\n" + " \n" + "
Default Quantum\n" + " \n" + "
Tasks Running\n" + " \n" + "
\n" + "
\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
Tasks
IDNameReferencesStateQuantum
\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
Memory Usage Summary
\n" + "
\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
Memory Contexts
IDNameReferencesTotalUseInUseMaxUseBlockSizePoolsHiWaterLoWater
\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + "\n" + " \n" + " \n" + "
\n" + "
\n"; diff --git a/contrib/bind-9.5.2/bin/named/builtin.c b/contrib/bind-9.5.2/bin/named/builtin.c new file mode 100644 index 0000000000..7927737d68 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/builtin.c @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001-2003 Internet Software Consortium. + * + * 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: builtin.c,v 1.12 2007/06/19 23:46:59 tbox Exp $ */ + +/*! \file + * \brief + * The built-in "version", "hostname", "id", "authors" and "empty" databases. + */ + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +typedef struct builtin builtin_t; + +static isc_result_t do_version_lookup(dns_sdblookup_t *lookup); +static isc_result_t do_hostname_lookup(dns_sdblookup_t *lookup); +static isc_result_t do_authors_lookup(dns_sdblookup_t *lookup); +static isc_result_t do_id_lookup(dns_sdblookup_t *lookup); +static isc_result_t do_empty_lookup(dns_sdblookup_t *lookup); + +/* + * We can't use function pointers as the db_data directly + * because ANSI C does not guarantee that function pointers + * can safely be cast to void pointers and back. + */ + +struct builtin { + isc_result_t (*do_lookup)(dns_sdblookup_t *lookup); + char *server; + char *contact; +}; + +static builtin_t version_builtin = { do_version_lookup, NULL, NULL }; +static builtin_t hostname_builtin = { do_hostname_lookup, NULL, NULL }; +static builtin_t authors_builtin = { do_authors_lookup, NULL, NULL }; +static builtin_t id_builtin = { do_id_lookup, NULL, NULL }; +static builtin_t empty_builtin = { do_empty_lookup, NULL, NULL }; + +static dns_sdbimplementation_t *builtin_impl; + +static isc_result_t +builtin_lookup(const char *zone, const char *name, void *dbdata, + dns_sdblookup_t *lookup) +{ + builtin_t *b = (builtin_t *) dbdata; + + UNUSED(zone); + + if (strcmp(name, "@") == 0) + return (b->do_lookup(lookup)); + else + return (ISC_R_NOTFOUND); +} + +static isc_result_t +put_txt(dns_sdblookup_t *lookup, const char *text) { + unsigned char buf[256]; + unsigned int len = strlen(text); + if (len > 255) + len = 255; /* Silently truncate */ + buf[0] = len; + memcpy(&buf[1], text, len); + return (dns_sdb_putrdata(lookup, dns_rdatatype_txt, 0, buf, len + 1)); +} + +static isc_result_t +do_version_lookup(dns_sdblookup_t *lookup) { + if (ns_g_server->version_set) { + if (ns_g_server->version == NULL) + return (ISC_R_SUCCESS); + else + return (put_txt(lookup, ns_g_server->version)); + } else { + return (put_txt(lookup, ns_g_version)); + } +} + +static isc_result_t +do_hostname_lookup(dns_sdblookup_t *lookup) { + if (ns_g_server->hostname_set) { + if (ns_g_server->hostname == NULL) + return (ISC_R_SUCCESS); + else + return (put_txt(lookup, ns_g_server->hostname)); + } else { + char buf[256]; + isc_result_t result = ns_os_gethostname(buf, sizeof(buf)); + if (result != ISC_R_SUCCESS) + return (result); + return (put_txt(lookup, buf)); + } +} + +static isc_result_t +do_authors_lookup(dns_sdblookup_t *lookup) { + isc_result_t result; + const char **p; + static const char *authors[] = { + "Mark Andrews", + "James Brister", + "Ben Cottrell", + "Michael Graff", + "Andreas Gustafsson", + "Bob Halley", + "David Lawrence", + "Danny Mayer", + "Damien Neil", + "Matt Nelson", + "Michael Sawyer", + "Brian Wellington", + NULL + }; + + /* + * If a version string is specified, disable the authors.bind zone. + */ + if (ns_g_server->version_set) + return (ISC_R_SUCCESS); + + for (p = authors; *p != NULL; p++) { + result = put_txt(lookup, *p); + if (result != ISC_R_SUCCESS) + return (result); + } + return (ISC_R_SUCCESS); +} + +static isc_result_t +do_id_lookup(dns_sdblookup_t *lookup) { + + if (ns_g_server->server_usehostname) { + char buf[256]; + isc_result_t result = ns_os_gethostname(buf, sizeof(buf)); + if (result != ISC_R_SUCCESS) + return (result); + return (put_txt(lookup, buf)); + } + + if (ns_g_server->server_id == NULL) + return (ISC_R_SUCCESS); + else + return (put_txt(lookup, ns_g_server->server_id)); +} + +static isc_result_t +do_empty_lookup(dns_sdblookup_t *lookup) { + + UNUSED(lookup); + return (ISC_R_SUCCESS); +} + +static isc_result_t +builtin_authority(const char *zone, void *dbdata, dns_sdblookup_t *lookup) { + isc_result_t result; + const char *contact = "hostmaster"; + const char *server = "@"; + builtin_t *b = (builtin_t *) dbdata; + + UNUSED(zone); + UNUSED(dbdata); + + if (b == &empty_builtin) { + server = "."; + contact = "."; + } else { + if (b->server != NULL) + server = b->server; + if (b->contact != NULL) + contact = b->contact; + } + + result = dns_sdb_putsoa(lookup, server, contact, 0); + if (result != ISC_R_SUCCESS) + return (ISC_R_FAILURE); + + result = dns_sdb_putrr(lookup, "ns", 0, server); + if (result != ISC_R_SUCCESS) + return (ISC_R_FAILURE); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +builtin_create(const char *zone, int argc, char **argv, + void *driverdata, void **dbdata) +{ + REQUIRE(argc >= 1); + + UNUSED(zone); + UNUSED(driverdata); + + if (strcmp(argv[0], "empty") == 0) { + if (argc != 3) + return (DNS_R_SYNTAX); + } else if (argc != 1) + return (DNS_R_SYNTAX); + + if (strcmp(argv[0], "version") == 0) + *dbdata = &version_builtin; + else if (strcmp(argv[0], "hostname") == 0) + *dbdata = &hostname_builtin; + else if (strcmp(argv[0], "authors") == 0) + *dbdata = &authors_builtin; + else if (strcmp(argv[0], "id") == 0) + *dbdata = &id_builtin; + else if (strcmp(argv[0], "empty") == 0) { + builtin_t *empty; + char *server; + char *contact; + /* + * We don't want built-in zones to fail. Fallback to + * the static configuration if memory allocation fails. + */ + empty = isc_mem_get(ns_g_mctx, sizeof(*empty)); + server = isc_mem_strdup(ns_g_mctx, argv[1]); + contact = isc_mem_strdup(ns_g_mctx, argv[2]); + if (empty == NULL || server == NULL || contact == NULL) { + *dbdata = &empty_builtin; + if (server != NULL) + isc_mem_free(ns_g_mctx, server); + if (contact != NULL) + isc_mem_free(ns_g_mctx, contact); + if (empty != NULL) + isc_mem_put(ns_g_mctx, empty, sizeof (*empty)); + } else { + memcpy(empty, &empty_builtin, sizeof (empty_builtin)); + empty->server = server; + empty->contact = contact; + *dbdata = empty; + } + } else + return (ISC_R_NOTIMPLEMENTED); + return (ISC_R_SUCCESS); +} + +static void +builtin_destroy(const char *zone, void *driverdata, void **dbdata) { + builtin_t *b = (builtin_t *) *dbdata; + + UNUSED(zone); + UNUSED(driverdata); + + /* + * Don't free the static versions. + */ + if (*dbdata == &version_builtin || *dbdata == &hostname_builtin || + *dbdata == &authors_builtin || *dbdata == &id_builtin || + *dbdata == &empty_builtin) + return; + + isc_mem_free(ns_g_mctx, b->server); + isc_mem_free(ns_g_mctx, b->contact); + isc_mem_put(ns_g_mctx, b, sizeof (*b)); +} + +static dns_sdbmethods_t builtin_methods = { + builtin_lookup, + builtin_authority, + NULL, /* allnodes */ + builtin_create, + builtin_destroy +}; + +isc_result_t +ns_builtin_init(void) { + RUNTIME_CHECK(dns_sdb_register("_builtin", &builtin_methods, NULL, + DNS_SDBFLAG_RELATIVEOWNER | + DNS_SDBFLAG_RELATIVERDATA, + ns_g_mctx, &builtin_impl) + == ISC_R_SUCCESS); + return (ISC_R_SUCCESS); +} + +void +ns_builtin_deinit(void) { + dns_sdb_unregister(&builtin_impl); +} diff --git a/contrib/bind-9.5.2/bin/named/client.c b/contrib/bind-9.5.2/bin/named/client.c new file mode 100644 index 0000000000..2e86115730 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/client.c @@ -0,0 +1,2779 @@ +/* + * Copyright (C) 2004-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 + * 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.250.16.10 2009/01/29 22:41:43 jinmei 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 + +/*** + *** Client + ***/ + +/*! \file + * Client Routines + * + * Important note! + * + * All client state changes, other than that from idle to listening, occur + * as a result of events. This guarantees serialization and avoids the + * need for locking. + * + * If a routine is ever created that allows someone other than the client's + * task to change the client, then the client will have to be locked. + */ + +#define NS_CLIENT_TRACE +#ifdef NS_CLIENT_TRACE +#define CTRACE(m) ns_client_log(client, \ + NS_LOGCATEGORY_CLIENT, \ + NS_LOGMODULE_CLIENT, \ + ISC_LOG_DEBUG(3), \ + "%s", (m)) +#define MTRACE(m) isc_log_write(ns_g_lctx, \ + NS_LOGCATEGORY_GENERAL, \ + NS_LOGMODULE_CLIENT, \ + ISC_LOG_DEBUG(3), \ + "clientmgr @%p: %s", manager, (m)) +#else +#define CTRACE(m) ((void)(m)) +#define MTRACE(m) ((void)(m)) +#endif + +#define TCP_CLIENT(c) (((c)->attributes & NS_CLIENTATTR_TCP) != 0) + +#define TCP_BUFFER_SIZE (65535 + 2) +#define SEND_BUFFER_SIZE 4096 +#define RECV_BUFFER_SIZE 4096 + +#ifdef ISC_PLATFORM_USETHREADS +#define NMCTXS 100 +/*%< + * Number of 'mctx pools' for clients. (Should this be configurable?) + * When enabling threads, we use a pool of memory contexts shared by + * client objects, since concurrent access to a shared context would cause + * heavy contentions. The above constant is expected to be enough for + * completely avoiding contentions among threads for an authoritative-only + * server. + */ +#else +#define NMCTXS 0 +/*%< + * If named with built without thread, simply share manager's context. Using + * a separate context in this case would simply waste memory. + */ +#endif + +/*% nameserver client manager structure */ +struct ns_clientmgr { + /* Unlocked. */ + unsigned int magic; + isc_mem_t * mctx; + isc_taskmgr_t * taskmgr; + isc_timermgr_t * timermgr; + isc_mutex_t lock; + /* Locked by lock. */ + isc_boolean_t exiting; + client_list_t active; /*%< Active clients */ + client_list_t recursing; /*%< Recursing clients */ + client_list_t inactive; /*%< To be recycled */ +#if NMCTXS > 0 + /*%< mctx pool for clients. */ + unsigned int nextmctx; + isc_mem_t * mctxpool[NMCTXS]; +#endif +}; + +#define MANAGER_MAGIC ISC_MAGIC('N', 'S', 'C', 'm') +#define VALID_MANAGER(m) ISC_MAGIC_VALID(m, MANAGER_MAGIC) + +/*! + * Client object states. Ordering is significant: higher-numbered + * states are generally "more active", meaning that the client can + * have more dynamically allocated data, outstanding events, etc. + * In the list below, any such properties listed for state N + * also apply to any state > N. + * + * To force the client into a less active state, set client->newstate + * to that state and call exit_check(). This will cause any + * activities defined for higher-numbered states to be aborted. + */ + +#define NS_CLIENTSTATE_FREED 0 +/*%< + * The client object no longer exists. + */ + +#define NS_CLIENTSTATE_INACTIVE 1 +/*%< + * The client object exists and has a task and timer. + * Its "query" struct and sendbuf are initialized. + * It is on the client manager's list of inactive clients. + * It has a message and OPT, both in the reset state. + */ + +#define NS_CLIENTSTATE_READY 2 +/*%< + * The client object is either a TCP or a UDP one, and + * it is associated with a network interface. It is on the + * client manager's list of active clients. + * + * If it is a TCP client object, it has a TCP listener socket + * and an outstanding TCP listen request. + * + * If it is a UDP client object, it has a UDP listener socket + * and an outstanding UDP receive request. + */ + +#define NS_CLIENTSTATE_READING 3 +/*%< + * The client object is a TCP client object that has received + * a connection. It has a tcpsocket, tcpmsg, TCP quota, and an + * outstanding TCP read request. This state is not used for + * UDP client objects. + */ + +#define NS_CLIENTSTATE_WORKING 4 +/*%< + * The client object has received a request and is working + * on it. It has a view, and it may have any of a non-reset OPT, + * recursion quota, and an outstanding write request. + */ + +#define NS_CLIENTSTATE_MAX 9 +/*%< + * Sentinel value used to indicate "no state". When client->newstate + * has this value, we are not attempting to exit the current state. + * Must be greater than any valid state. + */ + +/* + * Enable ns_client_dropport() by default. + */ +#ifndef NS_CLIENT_DROPPORT +#define NS_CLIENT_DROPPORT 1 +#endif + +unsigned int ns_client_requests; + +static void client_read(ns_client_t *client); +static void client_accept(ns_client_t *client); +static void client_udprecv(ns_client_t *client); +static void clientmgr_destroy(ns_clientmgr_t *manager); +static isc_boolean_t exit_check(ns_client_t *client); +static void ns_client_endrequest(ns_client_t *client); +static void ns_client_checkactive(ns_client_t *client); +static void client_start(isc_task_t *task, isc_event_t *event); +static void client_request(isc_task_t *task, isc_event_t *event); +static void ns_client_dumpmessage(ns_client_t *client, const char *reason); + +void +ns_client_recursing(ns_client_t *client) { + REQUIRE(NS_CLIENT_VALID(client)); + + LOCK(&client->manager->lock); + ISC_LIST_UNLINK(*client->list, client, link); + ISC_LIST_APPEND(client->manager->recursing, client, link); + client->list = &client->manager->recursing; + UNLOCK(&client->manager->lock); +} + +void +ns_client_killoldestquery(ns_client_t *client) { + ns_client_t *oldest; + REQUIRE(NS_CLIENT_VALID(client)); + + LOCK(&client->manager->lock); + oldest = ISC_LIST_HEAD(client->manager->recursing); + if (oldest != NULL) { + ns_query_cancel(oldest); + ISC_LIST_UNLINK(*oldest->list, oldest, link); + ISC_LIST_APPEND(client->manager->active, oldest, link); + oldest->list = &client->manager->active; + } + UNLOCK(&client->manager->lock); +} + +void +ns_client_settimeout(ns_client_t *client, unsigned int seconds) { + isc_result_t result; + isc_interval_t interval; + + isc_interval_set(&interval, seconds, 0); + result = isc_timer_reset(client->timer, isc_timertype_once, NULL, + &interval, ISC_FALSE); + client->timerset = ISC_TRUE; + if (result != ISC_R_SUCCESS) { + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_ERROR, + "setting timeout: %s", + isc_result_totext(result)); + /* Continue anyway. */ + } +} + +/*% + * Check for a deactivation or shutdown request and take appropriate + * action. Returns ISC_TRUE if either is in progress; in this case + * the caller must no longer use the client object as it may have been + * freed. + */ +static isc_boolean_t +exit_check(ns_client_t *client) { + ns_clientmgr_t *locked_manager = NULL; + ns_clientmgr_t *destroy_manager = NULL; + + REQUIRE(NS_CLIENT_VALID(client)); + + if (client->state <= client->newstate) + return (ISC_FALSE); /* Business as usual. */ + + INSIST(client->newstate < NS_CLIENTSTATE_WORKING); + + /* + * We need to detach from the view early when shutting down + * the server to break the following vicious circle: + * + * - The resolver will not shut down until the view refcount is zero + * - The view refcount does not go to zero until all clients detach + * - The client does not detach from the view until references is zero + * - references does not go to zero until the resolver has shut down + * + * Keep the view attached until any outstanding updates complete. + */ + if (client->nupdates == 0 && + client->newstate == NS_CLIENTSTATE_FREED && client->view != NULL) + dns_view_detach(&client->view); + + if (client->state == NS_CLIENTSTATE_WORKING) { + INSIST(client->newstate <= NS_CLIENTSTATE_READING); + /* + * Let the update processing complete. + */ + if (client->nupdates > 0) + return (ISC_TRUE); + /* + * We are trying to abort request processing. + */ + if (client->nsends > 0) { + isc_socket_t *socket; + if (TCP_CLIENT(client)) + socket = client->tcpsocket; + else + socket = client->udpsocket; + isc_socket_cancel(socket, client->task, + ISC_SOCKCANCEL_SEND); + } + + if (! (client->nsends == 0 && client->nrecvs == 0 && + client->references == 0)) + { + /* + * Still waiting for I/O cancel completion. + * or lingering references. + */ + return (ISC_TRUE); + } + /* + * I/O cancel is complete. Burn down all state + * related to the current request. Ensure that + * the client is on the active list and not the + * recursing list. + */ + LOCK(&client->manager->lock); + if (client->list == &client->manager->recursing) { + ISC_LIST_UNLINK(*client->list, client, link); + ISC_LIST_APPEND(client->manager->active, client, link); + client->list = &client->manager->active; + } + UNLOCK(&client->manager->lock); + ns_client_endrequest(client); + + client->state = NS_CLIENTSTATE_READING; + INSIST(client->recursionquota == NULL); + if (NS_CLIENTSTATE_READING == client->newstate) { + client_read(client); + client->newstate = NS_CLIENTSTATE_MAX; + return (ISC_TRUE); /* We're done. */ + } + } + + if (client->state == NS_CLIENTSTATE_READING) { + /* + * We are trying to abort the current TCP connection, + * if any. + */ + INSIST(client->recursionquota == NULL); + INSIST(client->newstate <= NS_CLIENTSTATE_READY); + if (client->nreads > 0) + dns_tcpmsg_cancelread(&client->tcpmsg); + if (! client->nreads == 0) { + /* Still waiting for read cancel completion. */ + return (ISC_TRUE); + } + + if (client->tcpmsg_valid) { + dns_tcpmsg_invalidate(&client->tcpmsg); + client->tcpmsg_valid = ISC_FALSE; + } + if (client->tcpsocket != NULL) { + CTRACE("closetcp"); + isc_socket_detach(&client->tcpsocket); + } + + if (client->tcpquota != NULL) + isc_quota_detach(&client->tcpquota); + + if (client->timerset) { + (void)isc_timer_reset(client->timer, + isc_timertype_inactive, + NULL, NULL, ISC_TRUE); + client->timerset = ISC_FALSE; + } + + client->peeraddr_valid = ISC_FALSE; + + client->state = NS_CLIENTSTATE_READY; + INSIST(client->recursionquota == NULL); + + /* + * Now the client is ready to accept a new TCP connection + * or UDP request, but we may have enough clients doing + * that already. Check whether this client needs to remain + * active and force it to go inactive if not. + */ + ns_client_checkactive(client); + + if (NS_CLIENTSTATE_READY == client->newstate) { + if (TCP_CLIENT(client)) { + client_accept(client); + } else + client_udprecv(client); + client->newstate = NS_CLIENTSTATE_MAX; + return (ISC_TRUE); + } + } + + if (client->state == NS_CLIENTSTATE_READY) { + INSIST(client->newstate <= NS_CLIENTSTATE_INACTIVE); + /* + * We are trying to enter the inactive state. + */ + if (client->naccepts > 0) + isc_socket_cancel(client->tcplistener, client->task, + ISC_SOCKCANCEL_ACCEPT); + + if (! (client->naccepts == 0)) { + /* Still waiting for accept cancel completion. */ + return (ISC_TRUE); + } + /* Accept cancel is complete. */ + + if (client->nrecvs > 0) + isc_socket_cancel(client->udpsocket, client->task, + ISC_SOCKCANCEL_RECV); + if (! (client->nrecvs == 0)) { + /* Still waiting for recv cancel completion. */ + return (ISC_TRUE); + } + /* Recv cancel is complete. */ + + if (client->nctls > 0) { + /* Still waiting for control event to be delivered */ + return (ISC_TRUE); + } + + /* Deactivate the client. */ + if (client->interface) + ns_interface_detach(&client->interface); + + INSIST(client->naccepts == 0); + INSIST(client->recursionquota == NULL); + if (client->tcplistener != NULL) + isc_socket_detach(&client->tcplistener); + + if (client->udpsocket != NULL) + isc_socket_detach(&client->udpsocket); + + if (client->dispatch != NULL) + dns_dispatch_detach(&client->dispatch); + + client->attributes = 0; + client->mortal = ISC_FALSE; + + LOCK(&client->manager->lock); + /* + * Put the client on the inactive list. If we are aiming for + * the "freed" state, it will be removed from the inactive + * list shortly, and we need to keep the manager locked until + * that has been done, lest the manager decide to reactivate + * the dying client inbetween. + */ + locked_manager = client->manager; + ISC_LIST_UNLINK(*client->list, client, link); + ISC_LIST_APPEND(client->manager->inactive, client, link); + client->list = &client->manager->inactive; + client->state = NS_CLIENTSTATE_INACTIVE; + INSIST(client->recursionquota == NULL); + + if (client->state == client->newstate) { + client->newstate = NS_CLIENTSTATE_MAX; + goto unlock; + } + } + + if (client->state == NS_CLIENTSTATE_INACTIVE) { + INSIST(client->newstate == NS_CLIENTSTATE_FREED); + /* + * We are trying to free the client. + * + * When "shuttingdown" is true, either the task has received + * its shutdown event or no shutdown event has ever been + * set up. Thus, we have no outstanding shutdown + * event at this point. + */ + REQUIRE(client->state == NS_CLIENTSTATE_INACTIVE); + + INSIST(client->recursionquota == NULL); + + ns_query_free(client); + isc_mem_put(client->mctx, client->recvbuf, RECV_BUFFER_SIZE); + isc_event_free((isc_event_t **)&client->sendevent); + isc_event_free((isc_event_t **)&client->recvevent); + isc_timer_detach(&client->timer); + + if (client->tcpbuf != NULL) + isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE); + if (client->opt != NULL) { + INSIST(dns_rdataset_isassociated(client->opt)); + dns_rdataset_disassociate(client->opt); + dns_message_puttemprdataset(client->message, &client->opt); + } + dns_message_destroy(&client->message); + if (client->manager != NULL) { + ns_clientmgr_t *manager = client->manager; + if (locked_manager == NULL) { + LOCK(&manager->lock); + locked_manager = manager; + } + ISC_LIST_UNLINK(*client->list, client, link); + client->list = NULL; + if (manager->exiting && + ISC_LIST_EMPTY(manager->active) && + ISC_LIST_EMPTY(manager->inactive) && + ISC_LIST_EMPTY(manager->recursing)) + destroy_manager = manager; + } + /* + * Detaching the task must be done after unlinking from + * the manager's lists because the manager accesses + * client->task. + */ + if (client->task != NULL) + isc_task_detach(&client->task); + + CTRACE("free"); + client->magic = 0; + isc_mem_putanddetach(&client->mctx, client, sizeof(*client)); + + goto unlock; + } + + unlock: + if (locked_manager != NULL) { + UNLOCK(&locked_manager->lock); + locked_manager = NULL; + } + + /* + * Only now is it safe to destroy the client manager (if needed), + * because we have accessed its lock for the last time. + */ + if (destroy_manager != NULL) + clientmgr_destroy(destroy_manager); + + return (ISC_TRUE); +} + +/*% + * The client's task has received the client's control event + * as part of the startup process. + */ +static void +client_start(isc_task_t *task, isc_event_t *event) { + ns_client_t *client = (ns_client_t *) event->ev_arg; + + INSIST(task == client->task); + + UNUSED(task); + + INSIST(client->nctls == 1); + client->nctls--; + + if (exit_check(client)) + return; + + if (TCP_CLIENT(client)) { + client_accept(client); + } else { + client_udprecv(client); + } +} + + +/*% + * The client's task has received a shutdown event. + */ +static void +client_shutdown(isc_task_t *task, isc_event_t *event) { + ns_client_t *client; + + REQUIRE(event != NULL); + REQUIRE(event->ev_type == ISC_TASKEVENT_SHUTDOWN); + client = event->ev_arg; + REQUIRE(NS_CLIENT_VALID(client)); + REQUIRE(task == client->task); + + UNUSED(task); + + CTRACE("shutdown"); + + isc_event_free(&event); + + if (client->shutdown != NULL) { + (client->shutdown)(client->shutdown_arg, ISC_R_SHUTTINGDOWN); + client->shutdown = NULL; + client->shutdown_arg = NULL; + } + + client->newstate = NS_CLIENTSTATE_FREED; + (void)exit_check(client); +} + +static void +ns_client_endrequest(ns_client_t *client) { + INSIST(client->naccepts == 0); + INSIST(client->nreads == 0); + INSIST(client->nsends == 0); + INSIST(client->nrecvs == 0); + INSIST(client->nupdates == 0); + INSIST(client->state == NS_CLIENTSTATE_WORKING); + + CTRACE("endrequest"); + + if (client->next != NULL) { + (client->next)(client); + client->next = NULL; + } + + if (client->view != NULL) + dns_view_detach(&client->view); + if (client->opt != NULL) { + INSIST(dns_rdataset_isassociated(client->opt)); + dns_rdataset_disassociate(client->opt); + dns_message_puttemprdataset(client->message, &client->opt); + } + + client->udpsize = 512; + client->extflags = 0; + client->ednsversion = -1; + dns_message_reset(client->message, DNS_MESSAGE_INTENTPARSE); + + if (client->recursionquota != NULL) + isc_quota_detach(&client->recursionquota); + + /* + * Clear all client attributes that are specific to + * the request; that's all except the TCP flag. + */ + client->attributes &= NS_CLIENTATTR_TCP; +} + +static void +ns_client_checkactive(ns_client_t *client) { + if (client->mortal) { + /* + * This client object should normally go inactive + * at this point, but if we have fewer active client + * objects than desired due to earlier quota exhaustion, + * keep it active to make up for the shortage. + */ + isc_boolean_t need_another_client = ISC_FALSE; + if (TCP_CLIENT(client)) { + LOCK(&client->interface->lock); + if (client->interface->ntcpcurrent < + client->interface->ntcptarget) + need_another_client = ISC_TRUE; + UNLOCK(&client->interface->lock); + } else { + /* + * The UDP client quota is enforced by making + * requests fail rather than by not listening + * for new ones. Therefore, there is always a + * full set of UDP clients listening. + */ + } + if (! need_another_client) { + /* + * We don't need this client object. Recycle it. + */ + if (client->newstate >= NS_CLIENTSTATE_INACTIVE) + client->newstate = NS_CLIENTSTATE_INACTIVE; + } + } +} + +void +ns_client_next(ns_client_t *client, isc_result_t result) { + int newstate; + + REQUIRE(NS_CLIENT_VALID(client)); + REQUIRE(client->state == NS_CLIENTSTATE_WORKING || + client->state == NS_CLIENTSTATE_READING); + + CTRACE("next"); + + if (result != ISC_R_SUCCESS) + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), + "request failed: %s", isc_result_totext(result)); + + /* + * An error processing a TCP request may have left + * the connection out of sync. To be safe, we always + * sever the connection when result != ISC_R_SUCCESS. + */ + if (result == ISC_R_SUCCESS && TCP_CLIENT(client)) + newstate = NS_CLIENTSTATE_READING; + else + newstate = NS_CLIENTSTATE_READY; + + if (client->newstate > newstate) + client->newstate = newstate; + (void)exit_check(client); +} + + +static void +client_senddone(isc_task_t *task, isc_event_t *event) { + ns_client_t *client; + isc_socketevent_t *sevent = (isc_socketevent_t *) event; + + REQUIRE(sevent != NULL); + REQUIRE(sevent->ev_type == ISC_SOCKEVENT_SENDDONE); + client = sevent->ev_arg; + REQUIRE(NS_CLIENT_VALID(client)); + REQUIRE(task == client->task); + REQUIRE(sevent == client->sendevent); + + UNUSED(task); + + CTRACE("senddone"); + + if (sevent->result != ISC_R_SUCCESS) + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_WARNING, + "error sending response: %s", + isc_result_totext(sevent->result)); + + INSIST(client->nsends > 0); + client->nsends--; + + if (client->tcpbuf != NULL) { + INSIST(TCP_CLIENT(client)); + isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE); + client->tcpbuf = NULL; + } + + if (exit_check(client)) + return; + + ns_client_next(client, ISC_R_SUCCESS); +} + +/*% + * We only want to fail with ISC_R_NOSPACE when called from + * ns_client_sendraw() and not when called from ns_client_send(), + * tcpbuffer is NULL when called from ns_client_sendraw() and + * length != 0. tcpbuffer != NULL when called from ns_client_send() + * and length == 0. + */ + +static isc_result_t +client_allocsendbuf(ns_client_t *client, isc_buffer_t *buffer, + isc_buffer_t *tcpbuffer, isc_uint32_t length, + unsigned char *sendbuf, unsigned char **datap) +{ + unsigned char *data; + isc_uint32_t bufsize; + isc_result_t result; + + INSIST(datap != NULL); + INSIST((tcpbuffer == NULL && length != 0) || + (tcpbuffer != NULL && length == 0)); + + if (TCP_CLIENT(client)) { + INSIST(client->tcpbuf == NULL); + if (length + 2 > TCP_BUFFER_SIZE) { + result = ISC_R_NOSPACE; + goto done; + } + client->tcpbuf = isc_mem_get(client->mctx, TCP_BUFFER_SIZE); + if (client->tcpbuf == NULL) { + result = ISC_R_NOMEMORY; + goto done; + } + data = client->tcpbuf; + if (tcpbuffer != NULL) { + isc_buffer_init(tcpbuffer, data, TCP_BUFFER_SIZE); + isc_buffer_init(buffer, data + 2, TCP_BUFFER_SIZE - 2); + } else { + isc_buffer_init(buffer, data, TCP_BUFFER_SIZE); + INSIST(length <= 0xffff); + isc_buffer_putuint16(buffer, (isc_uint16_t)length); + } + } else { + data = sendbuf; + if (client->udpsize < SEND_BUFFER_SIZE) + bufsize = client->udpsize; + else + bufsize = SEND_BUFFER_SIZE; + if (length > bufsize) { + result = ISC_R_NOSPACE; + goto done; + } + isc_buffer_init(buffer, data, bufsize); + } + *datap = data; + result = ISC_R_SUCCESS; + + done: + return (result); +} + +static isc_result_t +client_sendpkg(ns_client_t *client, isc_buffer_t *buffer) { + struct in6_pktinfo *pktinfo; + isc_result_t result; + isc_region_t r; + isc_sockaddr_t *address; + isc_socket_t *socket; + isc_netaddr_t netaddr; + int match; + unsigned int sockflags = ISC_SOCKFLAG_IMMEDIATE; + + if (TCP_CLIENT(client)) { + socket = client->tcpsocket; + address = NULL; + } else { + socket = client->udpsocket; + address = &client->peeraddr; + + isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); + if (ns_g_server->blackholeacl != NULL && + dns_acl_match(&netaddr, NULL, + ns_g_server->blackholeacl, + &ns_g_server->aclenv, + &match, NULL) == ISC_R_SUCCESS && + match > 0) + return (DNS_R_BLACKHOLED); + sockflags |= ISC_SOCKFLAG_NORETRY; + } + + if ((client->attributes & NS_CLIENTATTR_PKTINFO) != 0 && + (client->attributes & NS_CLIENTATTR_MULTICAST) == 0) + pktinfo = &client->pktinfo; + else + pktinfo = NULL; + + isc_buffer_usedregion(buffer, &r); + + CTRACE("sendto"); + + result = isc_socket_sendto2(socket, &r, client->task, + address, pktinfo, + client->sendevent, sockflags); + if (result == ISC_R_SUCCESS || result == ISC_R_INPROGRESS) { + client->nsends++; + if (result == ISC_R_SUCCESS) + client_senddone(client->task, + (isc_event_t *)client->sendevent); + result = ISC_R_SUCCESS; + } + return (result); +} + +void +ns_client_sendraw(ns_client_t *client, dns_message_t *message) { + isc_result_t result; + unsigned char *data; + isc_buffer_t buffer; + isc_region_t r; + isc_region_t *mr; + unsigned char sendbuf[SEND_BUFFER_SIZE]; + + REQUIRE(NS_CLIENT_VALID(client)); + + CTRACE("sendraw"); + + mr = dns_message_getrawmessage(message); + if (mr == NULL) { + result = ISC_R_UNEXPECTEDEND; + goto done; + } + + result = client_allocsendbuf(client, &buffer, NULL, mr->length, + sendbuf, &data); + if (result != ISC_R_SUCCESS) + goto done; + + /* + * Copy message to buffer and fixup id. + */ + isc_buffer_availableregion(&buffer, &r); + result = isc_buffer_copyregion(&buffer, mr); + if (result != ISC_R_SUCCESS) + goto done; + r.base[0] = (client->message->id >> 8) & 0xff; + r.base[1] = client->message->id & 0xff; + + result = client_sendpkg(client, &buffer); + if (result == ISC_R_SUCCESS) + return; + + done: + if (client->tcpbuf != NULL) { + isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE); + client->tcpbuf = NULL; + } + ns_client_next(client, result); +} + +void +ns_client_send(ns_client_t *client) { + isc_result_t result; + unsigned char *data; + isc_buffer_t buffer; + isc_buffer_t tcpbuffer; + isc_region_t r; + dns_compress_t cctx; + isc_boolean_t cleanup_cctx = ISC_FALSE; + unsigned char sendbuf[SEND_BUFFER_SIZE]; + unsigned int dnssec_opts; + unsigned int preferred_glue; + isc_boolean_t opt_included = ISC_FALSE; + + REQUIRE(NS_CLIENT_VALID(client)); + + CTRACE("send"); + + if ((client->attributes & NS_CLIENTATTR_RA) != 0) + client->message->flags |= DNS_MESSAGEFLAG_RA; + + if ((client->attributes & NS_CLIENTATTR_WANTDNSSEC) != 0) + dnssec_opts = 0; + else + dnssec_opts = DNS_MESSAGERENDER_OMITDNSSEC; + + preferred_glue = 0; + if (client->view != NULL) { + if (client->view->preferred_glue == dns_rdatatype_a) + preferred_glue = DNS_MESSAGERENDER_PREFER_A; + else if (client->view->preferred_glue == dns_rdatatype_aaaa) + preferred_glue = DNS_MESSAGERENDER_PREFER_AAAA; + } + + /* + * XXXRTH The following doesn't deal with TCP buffer resizing. + */ + result = client_allocsendbuf(client, &buffer, &tcpbuffer, 0, + sendbuf, &data); + if (result != ISC_R_SUCCESS) + goto done; + + result = dns_compress_init(&cctx, -1, client->mctx); + if (result != ISC_R_SUCCESS) + goto done; + cleanup_cctx = ISC_TRUE; + + result = dns_message_renderbegin(client->message, &cctx, &buffer); + if (result != ISC_R_SUCCESS) + goto done; + + if (client->opt != NULL) { + result = dns_message_setopt(client->message, client->opt); + opt_included = ISC_TRUE; + client->opt = NULL; + if (result != ISC_R_SUCCESS) + goto done; + } + result = dns_message_rendersection(client->message, + DNS_SECTION_QUESTION, 0); + if (result == ISC_R_NOSPACE) { + client->message->flags |= DNS_MESSAGEFLAG_TC; + goto renderend; + } + if (result != ISC_R_SUCCESS) + goto done; + result = dns_message_rendersection(client->message, + DNS_SECTION_ANSWER, + DNS_MESSAGERENDER_PARTIAL | + dnssec_opts); + if (result == ISC_R_NOSPACE) { + client->message->flags |= DNS_MESSAGEFLAG_TC; + goto renderend; + } + if (result != ISC_R_SUCCESS) + goto done; + result = dns_message_rendersection(client->message, + DNS_SECTION_AUTHORITY, + DNS_MESSAGERENDER_PARTIAL | + dnssec_opts); + if (result == ISC_R_NOSPACE) { + client->message->flags |= DNS_MESSAGEFLAG_TC; + goto renderend; + } + if (result != ISC_R_SUCCESS) + goto done; + result = dns_message_rendersection(client->message, + DNS_SECTION_ADDITIONAL, + preferred_glue | dnssec_opts); + if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE) + goto done; + renderend: + result = dns_message_renderend(client->message); + + if (result != ISC_R_SUCCESS) + goto done; + + if (cleanup_cctx) { + dns_compress_invalidate(&cctx); + cleanup_cctx = ISC_FALSE; + } + + if (TCP_CLIENT(client)) { + isc_buffer_usedregion(&buffer, &r); + isc_buffer_putuint16(&tcpbuffer, (isc_uint16_t) r.length); + isc_buffer_add(&tcpbuffer, r.length); + result = client_sendpkg(client, &tcpbuffer); + } else + result = client_sendpkg(client, &buffer); + + /* update statistics (XXXJT: is it okay to access message->xxxkey?) */ + isc_stats_increment(ns_g_server->nsstats, dns_nsstatscounter_response); + if (opt_included) { + isc_stats_increment(ns_g_server->nsstats, + dns_nsstatscounter_edns0out); + } + if (client->message->tsigkey != NULL) { + isc_stats_increment(ns_g_server->nsstats, + dns_nsstatscounter_tsigout); + } + if (client->message->sig0key != NULL) { + isc_stats_increment(ns_g_server->nsstats, + dns_nsstatscounter_sig0out); + } + if ((client->message->flags & DNS_MESSAGEFLAG_TC) != 0) + isc_stats_increment(ns_g_server->nsstats, + dns_nsstatscounter_truncatedresp); + + if (result == ISC_R_SUCCESS) + return; + + done: + if (client->tcpbuf != NULL) { + isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE); + client->tcpbuf = NULL; + } + + if (cleanup_cctx) + dns_compress_invalidate(&cctx); + + ns_client_next(client, result); +} + +#if NS_CLIENT_DROPPORT +#define DROPPORT_NO 0 +#define DROPPORT_REQUEST 1 +#define DROPPORT_RESPONSE 2 +/*% + * ns_client_dropport determines if certain requests / responses + * should be dropped based on the port number. + * + * Returns: + * \li 0: Don't drop. + * \li 1: Drop request. + * \li 2: Drop (error) response. + */ +static int +ns_client_dropport(in_port_t port) { + switch (port) { + case 7: /* echo */ + case 13: /* daytime */ + case 19: /* chargen */ + case 37: /* time */ + return (DROPPORT_REQUEST); + case 464: /* kpasswd */ + return (DROPPORT_RESPONSE); + } + return (DROPPORT_NO); +} +#endif + +void +ns_client_error(ns_client_t *client, isc_result_t result) { + dns_rcode_t rcode; + dns_message_t *message; + + REQUIRE(NS_CLIENT_VALID(client)); + + CTRACE("error"); + + message = client->message; + rcode = dns_result_torcode(result); + +#if NS_CLIENT_DROPPORT + /* + * Don't send FORMERR to ports on the drop port list. + */ + if (rcode == dns_rcode_formerr && + ns_client_dropport(isc_sockaddr_getport(&client->peeraddr)) != + DROPPORT_NO) { + char buf[64]; + isc_buffer_t b; + + isc_buffer_init(&b, buf, sizeof(buf) - 1); + if (dns_rcode_totext(rcode, &b) != ISC_R_SUCCESS) + isc_buffer_putstr(&b, "UNKNOWN RCODE"); + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), + "dropped error (%.*s) response: suspicious port", + (int)isc_buffer_usedlength(&b), buf); + ns_client_next(client, ISC_R_SUCCESS); + return; + } +#endif + + /* + * Message may be an in-progress reply that we had trouble + * with, in which case QR will be set. We need to clear QR before + * calling dns_message_reply() to avoid triggering an assertion. + */ + message->flags &= ~DNS_MESSAGEFLAG_QR; + /* + * AA and AD shouldn't be set. + */ + message->flags &= ~(DNS_MESSAGEFLAG_AA | DNS_MESSAGEFLAG_AD); + result = dns_message_reply(message, ISC_TRUE); + if (result != ISC_R_SUCCESS) { + /* + * It could be that we've got a query with a good header, + * but a bad question section, so we try again with + * want_question_section set to ISC_FALSE. + */ + result = dns_message_reply(message, ISC_FALSE); + if (result != ISC_R_SUCCESS) { + ns_client_next(client, result); + return; + } + } + message->rcode = rcode; + + /* + * FORMERR loop avoidance: If we sent a FORMERR message + * with the same ID to the same client less than two + * seconds ago, assume that we are in an infinite error + * packet dialog with a server for some protocol whose + * error responses look enough like DNS queries to + * elicit a FORMERR response. Drop a packet to break + * the loop. + */ + if (rcode == dns_rcode_formerr) { + if (isc_sockaddr_equal(&client->peeraddr, + &client->formerrcache.addr) && + message->id == client->formerrcache.id && + client->requesttime - client->formerrcache.time < 2) { + /* Drop packet. */ + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1), + "possible error packet loop, " + "FORMERR dropped"); + ns_client_next(client, result); + return; + } + client->formerrcache.addr = client->peeraddr; + client->formerrcache.time = client->requesttime; + client->formerrcache.id = message->id; + } + ns_client_send(client); +} + +static inline isc_result_t +client_addopt(ns_client_t *client) { + dns_rdataset_t *rdataset; + dns_rdatalist_t *rdatalist; + dns_rdata_t *rdata; + isc_result_t result; + dns_view_t *view; + dns_resolver_t *resolver; + isc_uint16_t udpsize; + + REQUIRE(client->opt == NULL); /* XXXRTH free old. */ + + rdatalist = NULL; + result = dns_message_gettemprdatalist(client->message, &rdatalist); + if (result != ISC_R_SUCCESS) + return (result); + rdata = NULL; + result = dns_message_gettemprdata(client->message, &rdata); + if (result != ISC_R_SUCCESS) + return (result); + rdataset = NULL; + result = dns_message_gettemprdataset(client->message, &rdataset); + if (result != ISC_R_SUCCESS) + return (result); + dns_rdataset_init(rdataset); + + rdatalist->type = dns_rdatatype_opt; + rdatalist->covers = 0; + + /* + * Set the maximum UDP buffer size. + */ + view = client->view; + resolver = (view != NULL) ? view->resolver : NULL; + if (resolver != NULL) + udpsize = dns_resolver_getudpsize(resolver); + else + udpsize = ns_g_udpsize; + rdatalist->rdclass = udpsize; + + /* + * Set EXTENDED-RCODE, VERSION and Z to 0. + */ + rdatalist->ttl = (client->extflags & DNS_MESSAGEEXTFLAG_REPLYPRESERVE); + + /* Set EDNS options if applicable */ + if (client->attributes & NS_CLIENTATTR_WANTNSID && + (ns_g_server->server_id != NULL || + ns_g_server->server_usehostname)) { + /* + * Space required for NSID data: + * 2 bytes for opt code + * + 2 bytes for NSID length + * + NSID itself + */ + char nsid[BUFSIZ], *nsidp; + isc_buffer_t *buffer = NULL; + + if (ns_g_server->server_usehostname) { + isc_result_t result; + result = ns_os_gethostname(nsid, sizeof(nsid)); + if (result != ISC_R_SUCCESS) { + goto no_nsid; + } + nsidp = nsid; + } else + nsidp = ns_g_server->server_id; + + rdata->length = strlen(nsidp) + 4; + result = isc_buffer_allocate(client->mctx, &buffer, + rdata->length); + if (result != ISC_R_SUCCESS) + goto no_nsid; + + isc_buffer_putuint16(buffer, DNS_OPT_NSID); + isc_buffer_putuint16(buffer, strlen(nsidp)); + isc_buffer_putstr(buffer, nsidp); + rdata->data = buffer->base; + dns_message_takebuffer(client->message, &buffer); + } else { +no_nsid: + rdata->data = NULL; + rdata->length = 0; + } + + rdata->rdclass = rdatalist->rdclass; + rdata->type = rdatalist->type; + rdata->flags = 0; + + ISC_LIST_INIT(rdatalist->rdata); + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) + == ISC_R_SUCCESS); + + client->opt = rdataset; + + return (ISC_R_SUCCESS); +} + +static inline isc_boolean_t +allowed(isc_netaddr_t *addr, dns_name_t *signer, dns_acl_t *acl) { + int match; + isc_result_t result; + + if (acl == NULL) + return (ISC_TRUE); + result = dns_acl_match(addr, signer, acl, &ns_g_server->aclenv, + &match, NULL); + if (result == ISC_R_SUCCESS && match > 0) + return (ISC_TRUE); + return (ISC_FALSE); +} + +/* + * Callback to see if a non-recursive query coming from 'srcaddr' to + * 'destaddr', with optional key 'mykey' for class 'rdclass' would be + * delivered to 'myview'. + * + * We run this unlocked as both the view list and the interface list + * are updated when the appropriate task has exclusivity. + */ +isc_boolean_t +ns_client_isself(dns_view_t *myview, dns_tsigkey_t *mykey, + isc_sockaddr_t *srcaddr, isc_sockaddr_t *dstaddr, + dns_rdataclass_t rdclass, void *arg) +{ + dns_view_t *view; + dns_tsigkey_t *key = NULL; + dns_name_t *tsig = NULL; + isc_netaddr_t netsrc; + isc_netaddr_t netdst; + + UNUSED(arg); + + if (!ns_interfacemgr_listeningon(ns_g_server->interfacemgr, dstaddr)) + return (ISC_FALSE); + + isc_netaddr_fromsockaddr(&netsrc, srcaddr); + isc_netaddr_fromsockaddr(&netdst, dstaddr); + + for (view = ISC_LIST_HEAD(ns_g_server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) { + + if (view->matchrecursiveonly) + continue; + + if (rdclass != view->rdclass) + continue; + + if (mykey != NULL) { + isc_boolean_t match; + isc_result_t result; + + result = dns_view_gettsig(view, &mykey->name, &key); + if (result != ISC_R_SUCCESS) + continue; + match = dst_key_compare(mykey->key, key->key); + dns_tsigkey_detach(&key); + if (!match) + continue; + tsig = dns_tsigkey_identity(mykey); + } + + if (allowed(&netsrc, tsig, view->matchclients) && + allowed(&netdst, tsig, view->matchdestinations)) + break; + } + return (ISC_TF(view == myview)); +} + +/* + * Handle an incoming request event from the socket (UDP case) + * or tcpmsg (TCP case). + */ +static void +client_request(isc_task_t *task, isc_event_t *event) { + ns_client_t *client; + isc_socketevent_t *sevent; + isc_result_t result; + isc_result_t sigresult = ISC_R_SUCCESS; + isc_buffer_t *buffer; + isc_buffer_t tbuffer; + dns_view_t *view; + dns_rdataset_t *opt; + dns_name_t *signame; + isc_boolean_t ra; /* Recursion available. */ + isc_netaddr_t netaddr; + isc_netaddr_t destaddr; + int match; + dns_messageid_t id; + unsigned int flags; + isc_boolean_t notimp; + dns_rdata_t rdata; + isc_uint16_t optcode; + + REQUIRE(event != NULL); + client = event->ev_arg; + REQUIRE(NS_CLIENT_VALID(client)); + REQUIRE(task == client->task); + + INSIST(client->recursionquota == NULL); + + INSIST(client->state == + TCP_CLIENT(client) ? + NS_CLIENTSTATE_READING : + NS_CLIENTSTATE_READY); + + ns_client_requests++; + + if (event->ev_type == ISC_SOCKEVENT_RECVDONE) { + INSIST(!TCP_CLIENT(client)); + sevent = (isc_socketevent_t *)event; + REQUIRE(sevent == client->recvevent); + isc_buffer_init(&tbuffer, sevent->region.base, sevent->n); + isc_buffer_add(&tbuffer, sevent->n); + buffer = &tbuffer; + result = sevent->result; + if (result == ISC_R_SUCCESS) { + client->peeraddr = sevent->address; + client->peeraddr_valid = ISC_TRUE; + } + if ((sevent->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0) { + client->attributes |= NS_CLIENTATTR_PKTINFO; + client->pktinfo = sevent->pktinfo; + } + if ((sevent->attributes & ISC_SOCKEVENTATTR_MULTICAST) != 0) + client->attributes |= NS_CLIENTATTR_MULTICAST; + client->nrecvs--; + } else { + INSIST(TCP_CLIENT(client)); + REQUIRE(event->ev_type == DNS_EVENT_TCPMSG); + REQUIRE(event->ev_sender == &client->tcpmsg); + buffer = &client->tcpmsg.buffer; + result = client->tcpmsg.result; + INSIST(client->nreads == 1); + /* + * client->peeraddr was set when the connection was accepted. + */ + client->nreads--; + } + + if (exit_check(client)) + goto cleanup; + client->state = client->newstate = NS_CLIENTSTATE_WORKING; + + isc_task_getcurrenttime(task, &client->requesttime); + client->now = client->requesttime; + + if (result != ISC_R_SUCCESS) { + if (TCP_CLIENT(client)) { + ns_client_next(client, result); + } else { + if (result != ISC_R_CANCELED) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, + ISC_LOG_ERROR, + "UDP client handler shutting " + "down due to fatal receive " + "error: %s", + isc_result_totext(result)); + isc_task_shutdown(client->task); + } + goto cleanup; + } + + isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); + +#if NS_CLIENT_DROPPORT + if (ns_client_dropport(isc_sockaddr_getport(&client->peeraddr)) == + DROPPORT_REQUEST) { + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), + "dropped request: suspicious port"); + ns_client_next(client, ISC_R_SUCCESS); + goto cleanup; + } +#endif + + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), + "%s request", + TCP_CLIENT(client) ? "TCP" : "UDP"); + + /* + * Check the blackhole ACL for UDP only, since TCP is done in + * client_newconn. + */ + if (!TCP_CLIENT(client)) { + + if (ns_g_server->blackholeacl != NULL && + dns_acl_match(&netaddr, NULL, ns_g_server->blackholeacl, + &ns_g_server->aclenv, + &match, NULL) == ISC_R_SUCCESS && + match > 0) + { + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), + "blackholed UDP datagram"); + ns_client_next(client, ISC_R_SUCCESS); + goto cleanup; + } + } + + /* + * Silently drop multicast requests for the present. + * XXXMPA look at when/if mDNS spec stabilizes. + */ + if ((client->attributes & NS_CLIENTATTR_MULTICAST) != 0) { + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2), + "dropping multicast request"); + ns_client_next(client, DNS_R_REFUSED); + goto cleanup; + } + + result = dns_message_peekheader(buffer, &id, &flags); + if (result != ISC_R_SUCCESS) { + /* + * There isn't enough header to determine whether + * this was a request or a response. Drop it. + */ + ns_client_next(client, result); + goto cleanup; + } + + /* + * The client object handles requests, not responses. + * If this is a UDP response, forward it to the dispatcher. + * If it's a TCP response, discard it here. + */ + if ((flags & DNS_MESSAGEFLAG_QR) != 0) { + if (TCP_CLIENT(client)) { + CTRACE("unexpected response"); + ns_client_next(client, DNS_R_FORMERR); + goto cleanup; + } else { + dns_dispatch_importrecv(client->dispatch, event); + ns_client_next(client, ISC_R_SUCCESS); + goto cleanup; + } + } + + /* + * Update some statistics counters. Don't count responses. + */ + if (isc_sockaddr_pf(&client->peeraddr) == PF_INET) { + isc_stats_increment(ns_g_server->nsstats, + dns_nsstatscounter_requestv4); + } else { + isc_stats_increment(ns_g_server->nsstats, + dns_nsstatscounter_requestv6); + } + if (TCP_CLIENT(client)) + isc_stats_increment(ns_g_server->nsstats, + dns_nsstatscounter_tcp); + + /* + * It's a request. Parse it. + */ + result = dns_message_parse(client->message, buffer, 0); + if (result != ISC_R_SUCCESS) { + /* + * Parsing the request failed. Send a response + * (typically FORMERR or SERVFAIL). + */ + ns_client_error(client, result); + goto cleanup; + } + + dns_opcodestats_increment(ns_g_server->opcodestats, + client->message->opcode); + switch (client->message->opcode) { + case dns_opcode_query: + case dns_opcode_update: + case dns_opcode_notify: + notimp = ISC_FALSE; + break; + case dns_opcode_iquery: + default: + notimp = ISC_TRUE; + break; + } + + client->message->rcode = dns_rcode_noerror; + + /* RFC1123 section 6.1.3.2 */ + if ((client->attributes & NS_CLIENTATTR_MULTICAST) != 0) + client->message->flags &= ~DNS_MESSAGEFLAG_RD; + + /* + * Deal with EDNS. + */ + opt = dns_message_getopt(client->message); + if (opt != NULL) { + /* + * Set the client's UDP buffer size. + */ + client->udpsize = opt->rdclass; + + /* + * If the requested UDP buffer size is less than 512, + * ignore it and use 512. + */ + if (client->udpsize < 512) + client->udpsize = 512; + + /* + * Get the flags out of the OPT record. + */ + client->extflags = (isc_uint16_t)(opt->ttl & 0xFFFF); + + /* + * Do we understand this version of EDNS? + * + * XXXRTH need library support for this! + */ + client->ednsversion = (opt->ttl & 0x00FF0000) >> 16; + if (client->ednsversion > 0) { + isc_stats_increment(ns_g_server->nsstats, + dns_nsstatscounter_badednsver); + result = client_addopt(client); + if (result == ISC_R_SUCCESS) + result = DNS_R_BADVERS; + ns_client_error(client, result); + goto cleanup; + } + + /* Check for NSID request */ + result = dns_rdataset_first(opt); + if (result == ISC_R_SUCCESS) { + dns_rdata_init(&rdata); + dns_rdataset_current(opt, &rdata); + if (rdata.length >= 2) { + isc_buffer_t nsidbuf; + isc_buffer_init(&nsidbuf, + rdata.data, rdata.length); + isc_buffer_add(&nsidbuf, rdata.length); + optcode = isc_buffer_getuint16(&nsidbuf); + if (optcode == DNS_OPT_NSID) + client->attributes |= + NS_CLIENTATTR_WANTNSID; + } + } + + isc_stats_increment(ns_g_server->nsstats, + dns_nsstatscounter_edns0in); + + /* + * Create an OPT for our reply. + */ + result = client_addopt(client); + if (result != ISC_R_SUCCESS) { + ns_client_error(client, result); + goto cleanup; + } + } + + if (client->message->rdclass == 0) { + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1), + "message class could not be determined"); + ns_client_dumpmessage(client, + "message class could not be determined"); + ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_FORMERR); + goto cleanup; + } + + /* + * Determine the destination address. If the receiving interface is + * bound to a specific address, we simply use it regardless of the + * address family. All IPv4 queries should fall into this case. + * Otherwise, if this is a TCP query, get the address from the + * receiving socket (this needs a system call and can be heavy). + * For IPv6 UDP queries, we get this from the pktinfo structure (if + * supported). + * If all the attempts fail (this can happen due to memory shortage, + * etc), we regard this as an error for safety. + */ + if ((client->interface->flags & NS_INTERFACEFLAG_ANYADDR) == 0) + isc_netaddr_fromsockaddr(&destaddr, &client->interface->addr); + else { + result = ISC_R_FAILURE; + + if (TCP_CLIENT(client)) { + isc_sockaddr_t destsockaddr; + + result = isc_socket_getsockname(client->tcpsocket, + &destsockaddr); + if (result == ISC_R_SUCCESS) + isc_netaddr_fromsockaddr(&destaddr, + &destsockaddr); + } + if (result != ISC_R_SUCCESS && + client->interface->addr.type.sa.sa_family == AF_INET6 && + (client->attributes & NS_CLIENTATTR_PKTINFO) != 0) { + isc_uint32_t zone = 0; + + /* + * XXXJT technically, we should convert the receiving + * interface ID to a proper scope zone ID. However, + * due to the fact there is no standard API for this, + * we only handle link-local addresses and use the + * interface index as link ID. Despite the assumption, + * it should cover most typical cases. + */ + if (IN6_IS_ADDR_LINKLOCAL(&client->pktinfo.ipi6_addr)) + zone = (isc_uint32_t)client->pktinfo.ipi6_ifindex; + + isc_netaddr_fromin6(&destaddr, + &client->pktinfo.ipi6_addr); + isc_netaddr_setzone(&destaddr, zone); + result = ISC_R_SUCCESS; + } + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "failed to get request's " + "destination: %s", + isc_result_totext(result)); + ns_client_next(client, ISC_R_SUCCESS); + goto cleanup; + } + } + + /* + * Find a view that matches the client's source address. + */ + for (view = ISC_LIST_HEAD(ns_g_server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) { + if (client->message->rdclass == view->rdclass || + client->message->rdclass == dns_rdataclass_any) + { + dns_name_t *tsig = NULL; + + sigresult = dns_message_rechecksig(client->message, + view); + if (sigresult == ISC_R_SUCCESS) + tsig = dns_tsigkey_identity(client->message->tsigkey); + + if (allowed(&netaddr, tsig, view->matchclients) && + allowed(&destaddr, tsig, view->matchdestinations) && + !((client->message->flags & DNS_MESSAGEFLAG_RD) + == 0 && view->matchrecursiveonly)) + { + dns_view_attach(view, &client->view); + break; + } + } + } + + if (view == NULL) { + char classname[DNS_RDATACLASS_FORMATSIZE]; + + /* + * Do a dummy TSIG verification attempt so that the + * response will have a TSIG if the query did, as + * required by RFC2845. + */ + isc_buffer_t b; + isc_region_t *r; + + dns_message_resetsig(client->message); + + r = dns_message_getrawmessage(client->message); + isc_buffer_init(&b, r->base, r->length); + isc_buffer_add(&b, r->length); + (void)dns_tsig_verify(&b, client->message, NULL, NULL); + + dns_rdataclass_format(client->message->rdclass, classname, + sizeof(classname)); + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1), + "no matching view in class '%s'", classname); + ns_client_dumpmessage(client, "no matching view in class"); + ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_REFUSED); + goto cleanup; + } + + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(5), + "using view '%s'", view->name); + + /* + * Check for a signature. We log bad signatures regardless of + * whether they ultimately cause the request to be rejected or + * not. We do not log the lack of a signature unless we are + * debugging. + */ + client->signer = NULL; + dns_name_init(&client->signername, NULL); + result = dns_message_signer(client->message, &client->signername); + if (result != ISC_R_NOTFOUND) { + signame = NULL; + if (dns_message_gettsig(client->message, &signame) != NULL) { + isc_stats_increment(ns_g_server->nsstats, + dns_nsstatscounter_tsigin); + } else { + isc_stats_increment(ns_g_server->nsstats, + dns_nsstatscounter_sig0in); + } + + } + if (result == ISC_R_SUCCESS) { + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), + "request has valid signature"); + client->signer = &client->signername; + } else if (result == ISC_R_NOTFOUND) { + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), + "request is not signed"); + } else if (result == DNS_R_NOIDENTITY) { + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), + "request is signed by a nonauthoritative key"); + } else { + char tsigrcode[64]; + isc_buffer_t b; + dns_rcode_t status; + isc_result_t tresult; + + /* There is a signature, but it is bad. */ + isc_stats_increment(ns_g_server->nsstats, + dns_nsstatscounter_invalidsig); + signame = NULL; + if (dns_message_gettsig(client->message, &signame) != NULL) { + char namebuf[DNS_NAME_FORMATSIZE]; + char cnamebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(signame, namebuf, sizeof(namebuf)); + status = client->message->tsigstatus; + isc_buffer_init(&b, tsigrcode, sizeof(tsigrcode) - 1); + tresult = dns_tsigrcode_totext(status, &b); + INSIST(tresult == ISC_R_SUCCESS); + tsigrcode[isc_buffer_usedlength(&b)] = '\0'; + if (client->message->tsigkey->generated) { + dns_name_format(client->message->tsigkey->creator, + cnamebuf, sizeof(cnamebuf)); + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, + ISC_LOG_ERROR, + "request has invalid signature: " + "TSIG %s (%s): %s (%s)", namebuf, + cnamebuf, + isc_result_totext(result), + tsigrcode); + } else { + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, + ISC_LOG_ERROR, + "request has invalid signature: " + "TSIG %s: %s (%s)", namebuf, + isc_result_totext(result), + tsigrcode); + } + } else { + status = client->message->sig0status; + isc_buffer_init(&b, tsigrcode, sizeof(tsigrcode) - 1); + tresult = dns_tsigrcode_totext(status, &b); + INSIST(tresult == ISC_R_SUCCESS); + tsigrcode[isc_buffer_usedlength(&b)] = '\0'; + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, ISC_LOG_ERROR, + "request has invalid signature: %s (%s)", + isc_result_totext(result), tsigrcode); + } + /* + * Accept update messages signed by unknown keys so that + * update forwarding works transparently through slaves + * that don't have all the same keys as the master. + */ + if (!(client->message->tsigstatus == dns_tsigerror_badkey && + client->message->opcode == dns_opcode_update)) { + ns_client_error(client, sigresult); + goto cleanup; + } + } + + /* + * Decide whether recursive service is available to this client. + * We do this here rather than in the query code so that we can + * set the RA bit correctly on all kinds of responses, not just + * responses to ordinary queries. Note if you can't query the + * cache there is no point in setting RA. + */ + ra = ISC_FALSE; + if (client->view->resolver != NULL && + client->view->recursion == ISC_TRUE && + ns_client_checkaclsilent(client, NULL, + client->view->recursionacl, + ISC_TRUE) == ISC_R_SUCCESS && + ns_client_checkaclsilent(client, NULL, + client->view->queryacl, + ISC_TRUE) == ISC_R_SUCCESS && + ns_client_checkaclsilent(client, &client->interface->addr, + client->view->recursiononacl, + ISC_TRUE) == ISC_R_SUCCESS && + ns_client_checkaclsilent(client, &client->interface->addr, + client->view->queryonacl, + ISC_TRUE) == ISC_R_SUCCESS) + ra = ISC_TRUE; + + if (ra == ISC_TRUE) + client->attributes |= NS_CLIENTATTR_RA; + + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_CLIENT, + ISC_LOG_DEBUG(3), ra ? "recursion available" : + "recursion not available"); + + /* + * Adjust maximum UDP response size for this client. + */ + if (client->udpsize > 512) { + dns_peer_t *peer = NULL; + isc_uint16_t udpsize = view->maxudp; + (void) dns_peerlist_peerbyaddr(view->peers, &netaddr, &peer); + if (peer != NULL) + dns_peer_getmaxudp(peer, &udpsize); + if (client->udpsize > udpsize) + client->udpsize = udpsize; + } + + /* + * Dispatch the request. + */ + switch (client->message->opcode) { + case dns_opcode_query: + CTRACE("query"); + ns_query_start(client); + break; + case dns_opcode_update: + CTRACE("update"); + ns_client_settimeout(client, 60); + ns_update_start(client, sigresult); + break; + case dns_opcode_notify: + CTRACE("notify"); + ns_client_settimeout(client, 60); + ns_notify_start(client); + break; + case dns_opcode_iquery: + CTRACE("iquery"); + ns_client_error(client, DNS_R_NOTIMP); + break; + default: + CTRACE("unknown opcode"); + ns_client_error(client, DNS_R_NOTIMP); + } + + cleanup: + return; +} + +static void +client_timeout(isc_task_t *task, isc_event_t *event) { + ns_client_t *client; + + REQUIRE(event != NULL); + REQUIRE(event->ev_type == ISC_TIMEREVENT_LIFE || + event->ev_type == ISC_TIMEREVENT_IDLE); + client = event->ev_arg; + REQUIRE(NS_CLIENT_VALID(client)); + REQUIRE(task == client->task); + REQUIRE(client->timer != NULL); + + UNUSED(task); + + CTRACE("timeout"); + + isc_event_free(&event); + + if (client->shutdown != NULL) { + (client->shutdown)(client->shutdown_arg, ISC_R_TIMEDOUT); + client->shutdown = NULL; + client->shutdown_arg = NULL; + } + + if (client->newstate > NS_CLIENTSTATE_READY) + client->newstate = NS_CLIENTSTATE_READY; + (void)exit_check(client); +} + +static isc_result_t +get_clientmctx(ns_clientmgr_t *manager, isc_mem_t **mctxp) { + isc_mem_t *clientmctx; +#if NMCTXS > 0 + isc_result_t result; +#endif + + /* + * Caller must be holding the manager lock. + */ +#if NMCTXS > 0 + INSIST(manager->nextmctx < NMCTXS); + clientmctx = manager->mctxpool[manager->nextmctx]; + if (clientmctx == NULL) { + result = isc_mem_create(0, 0, &clientmctx); + if (result != ISC_R_SUCCESS) + return (result); + isc_mem_setname(clientmctx, "client", NULL); + + manager->mctxpool[manager->nextmctx] = clientmctx; + } + manager->nextmctx++; + if (manager->nextmctx == NMCTXS) + manager->nextmctx = 0; +#else + clientmctx = manager->mctx; +#endif + + isc_mem_attach(clientmctx, mctxp); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +client_create(ns_clientmgr_t *manager, ns_client_t **clientp) { + ns_client_t *client; + isc_result_t result; + isc_mem_t *mctx = NULL; + + /* + * Caller must be holding the manager lock. + * + * Note: creating a client does not add the client to the + * manager's client list or set the client's manager pointer. + * The caller is responsible for that. + */ + + REQUIRE(clientp != NULL && *clientp == NULL); + + result = get_clientmctx(manager, &mctx); + if (result != ISC_R_SUCCESS) + return (result); + + client = isc_mem_get(mctx, sizeof(*client)); + if (client == NULL) { + isc_mem_detach(&mctx); + return (ISC_R_NOMEMORY); + } + client->mctx = mctx; + + client->task = NULL; + result = isc_task_create(manager->taskmgr, 0, &client->task); + if (result != ISC_R_SUCCESS) + goto cleanup_client; + isc_task_setname(client->task, "client", client); + + client->timer = NULL; + result = isc_timer_create(manager->timermgr, isc_timertype_inactive, + NULL, NULL, client->task, client_timeout, + client, &client->timer); + if (result != ISC_R_SUCCESS) + goto cleanup_task; + client->timerset = ISC_FALSE; + + client->message = NULL; + result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTPARSE, + &client->message); + if (result != ISC_R_SUCCESS) + goto cleanup_timer; + + /* XXXRTH Hardwired constants */ + + client->sendevent = (isc_socketevent_t *) + isc_event_allocate(client->mctx, client, + ISC_SOCKEVENT_SENDDONE, + client_senddone, client, + sizeof(isc_socketevent_t)); + if (client->sendevent == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup_message; + } + + client->recvbuf = isc_mem_get(client->mctx, RECV_BUFFER_SIZE); + if (client->recvbuf == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup_sendevent; + } + + client->recvevent = (isc_socketevent_t *) + isc_event_allocate(client->mctx, client, + ISC_SOCKEVENT_RECVDONE, + client_request, client, + sizeof(isc_socketevent_t)); + if (client->recvevent == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup_recvbuf; + } + + client->magic = NS_CLIENT_MAGIC; + client->manager = NULL; + client->state = NS_CLIENTSTATE_INACTIVE; + client->newstate = NS_CLIENTSTATE_MAX; + client->naccepts = 0; + client->nreads = 0; + client->nsends = 0; + client->nrecvs = 0; + client->nupdates = 0; + client->nctls = 0; + client->references = 0; + client->attributes = 0; + client->view = NULL; + client->dispatch = NULL; + client->udpsocket = NULL; + client->tcplistener = NULL; + client->tcpsocket = NULL; + client->tcpmsg_valid = ISC_FALSE; + client->tcpbuf = NULL; + client->opt = NULL; + client->udpsize = 512; + client->extflags = 0; + client->ednsversion = -1; + client->next = NULL; + client->shutdown = NULL; + client->shutdown_arg = NULL; + dns_name_init(&client->signername, NULL); + client->mortal = ISC_FALSE; + client->tcpquota = NULL; + client->recursionquota = NULL; + client->interface = NULL; + client->peeraddr_valid = ISC_FALSE; + ISC_EVENT_INIT(&client->ctlevent, sizeof(client->ctlevent), 0, NULL, + NS_EVENT_CLIENTCONTROL, client_start, client, client, + NULL, NULL); + /* + * Initialize FORMERR cache to sentinel value that will not match + * any actual FORMERR response. + */ + isc_sockaddr_any(&client->formerrcache.addr); + client->formerrcache.time = 0; + client->formerrcache.id = 0; + ISC_LINK_INIT(client, link); + client->list = NULL; + + /* + * We call the init routines for the various kinds of client here, + * after we have created an otherwise valid client, because some + * of them call routines that REQUIRE(NS_CLIENT_VALID(client)). + */ + result = ns_query_init(client); + if (result != ISC_R_SUCCESS) + goto cleanup_recvevent; + + result = isc_task_onshutdown(client->task, client_shutdown, client); + if (result != ISC_R_SUCCESS) + goto cleanup_query; + + CTRACE("create"); + + *clientp = client; + + return (ISC_R_SUCCESS); + + cleanup_query: + ns_query_free(client); + + cleanup_recvevent: + isc_event_free((isc_event_t **)&client->recvevent); + + cleanup_recvbuf: + isc_mem_put(client->mctx, client->recvbuf, RECV_BUFFER_SIZE); + + cleanup_sendevent: + isc_event_free((isc_event_t **)&client->sendevent); + + client->magic = 0; + + cleanup_message: + dns_message_destroy(&client->message); + + cleanup_timer: + isc_timer_detach(&client->timer); + + cleanup_task: + isc_task_detach(&client->task); + + cleanup_client: + isc_mem_putanddetach(&client->mctx, client, sizeof(*client)); + + return (result); +} + +static void +client_read(ns_client_t *client) { + isc_result_t result; + + CTRACE("read"); + + result = dns_tcpmsg_readmessage(&client->tcpmsg, client->task, + client_request, client); + if (result != ISC_R_SUCCESS) + goto fail; + + /* + * Set a timeout to limit the amount of time we will wait + * for a request on this TCP connection. + */ + ns_client_settimeout(client, 30); + + client->state = client->newstate = NS_CLIENTSTATE_READING; + INSIST(client->nreads == 0); + INSIST(client->recursionquota == NULL); + client->nreads++; + + return; + fail: + ns_client_next(client, result); +} + +static void +client_newconn(isc_task_t *task, isc_event_t *event) { + ns_client_t *client = event->ev_arg; + isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event; + isc_result_t result; + + REQUIRE(event->ev_type == ISC_SOCKEVENT_NEWCONN); + REQUIRE(NS_CLIENT_VALID(client)); + REQUIRE(client->task == task); + + UNUSED(task); + + INSIST(client->state == NS_CLIENTSTATE_READY); + + INSIST(client->naccepts == 1); + client->naccepts--; + + LOCK(&client->interface->lock); + INSIST(client->interface->ntcpcurrent > 0); + client->interface->ntcpcurrent--; + UNLOCK(&client->interface->lock); + + /* + * We must take ownership of the new socket before the exit + * check to make sure it gets destroyed if we decide to exit. + */ + if (nevent->result == ISC_R_SUCCESS) { + client->tcpsocket = nevent->newsocket; + isc_socket_setname(client->tcpsocket, "client-tcp", NULL); + client->state = NS_CLIENTSTATE_READING; + INSIST(client->recursionquota == NULL); + + (void)isc_socket_getpeername(client->tcpsocket, + &client->peeraddr); + client->peeraddr_valid = ISC_TRUE; + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), + "new TCP connection"); + } else { + /* + * XXXRTH What should we do? We're trying to accept but + * it didn't work. If we just give up, then TCP + * service may eventually stop. + * + * For now, we just go idle. + * + * Going idle is probably the right thing if the + * I/O was canceled. + */ + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), + "accept failed: %s", + isc_result_totext(nevent->result)); + } + + if (exit_check(client)) + goto freeevent; + + if (nevent->result == ISC_R_SUCCESS) { + int match; + isc_netaddr_t netaddr; + + isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); + + if (ns_g_server->blackholeacl != NULL && + dns_acl_match(&netaddr, NULL, + ns_g_server->blackholeacl, + &ns_g_server->aclenv, + &match, NULL) == ISC_R_SUCCESS && + match > 0) + { + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), + "blackholed connection attempt"); + client->newstate = NS_CLIENTSTATE_READY; + (void)exit_check(client); + goto freeevent; + } + + INSIST(client->tcpmsg_valid == ISC_FALSE); + dns_tcpmsg_init(client->mctx, client->tcpsocket, + &client->tcpmsg); + client->tcpmsg_valid = ISC_TRUE; + + /* + * Let a new client take our place immediately, before + * we wait for a request packet. If we don't, + * telnetting to port 53 (once per CPU) will + * deny service to legitimate TCP clients. + */ + result = isc_quota_attach(&ns_g_server->tcpquota, + &client->tcpquota); + if (result == ISC_R_SUCCESS) + result = ns_client_replace(client); + if (result != ISC_R_SUCCESS) { + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_WARNING, + "no more TCP clients: %s", + isc_result_totext(result)); + } + + client_read(client); + } + + freeevent: + isc_event_free(&event); +} + +static void +client_accept(ns_client_t *client) { + isc_result_t result; + + CTRACE("accept"); + + result = isc_socket_accept(client->tcplistener, client->task, + client_newconn, client); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_socket_accept() failed: %s", + isc_result_totext(result)); + /* + * XXXRTH What should we do? We're trying to accept but + * it didn't work. If we just give up, then TCP + * service may eventually stop. + * + * For now, we just go idle. + */ + return; + } + INSIST(client->naccepts == 0); + client->naccepts++; + LOCK(&client->interface->lock); + client->interface->ntcpcurrent++; + UNLOCK(&client->interface->lock); +} + +static void +client_udprecv(ns_client_t *client) { + isc_result_t result; + isc_region_t r; + + CTRACE("udprecv"); + + r.base = client->recvbuf; + r.length = RECV_BUFFER_SIZE; + result = isc_socket_recv2(client->udpsocket, &r, 1, + client->task, client->recvevent, 0); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_socket_recv2() failed: %s", + isc_result_totext(result)); + /* + * This cannot happen in the current implementation, since + * isc_socket_recv2() cannot fail if flags == 0. + * + * If this does fail, we just go idle. + */ + return; + } + INSIST(client->nrecvs == 0); + client->nrecvs++; +} + +void +ns_client_attach(ns_client_t *source, ns_client_t **targetp) { + REQUIRE(NS_CLIENT_VALID(source)); + REQUIRE(targetp != NULL && *targetp == NULL); + + source->references++; + ns_client_log(source, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), + "ns_client_attach: ref = %d", source->references); + *targetp = source; +} + +void +ns_client_detach(ns_client_t **clientp) { + ns_client_t *client = *clientp; + + client->references--; + INSIST(client->references >= 0); + *clientp = NULL; + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), + "ns_client_detach: ref = %d", client->references); + (void)exit_check(client); +} + +isc_boolean_t +ns_client_shuttingdown(ns_client_t *client) { + return (ISC_TF(client->newstate == NS_CLIENTSTATE_FREED)); +} + +isc_result_t +ns_client_replace(ns_client_t *client) { + isc_result_t result; + + CTRACE("replace"); + + result = ns_clientmgr_createclients(client->manager, + 1, client->interface, + (TCP_CLIENT(client) ? + ISC_TRUE : ISC_FALSE)); + if (result != ISC_R_SUCCESS) + return (result); + + /* + * The responsibility for listening for new requests is hereby + * transferred to the new client. Therefore, the old client + * should refrain from listening for any more requests. + */ + client->mortal = ISC_TRUE; + + return (ISC_R_SUCCESS); +} + +/*** + *** Client Manager + ***/ + +static void +clientmgr_destroy(ns_clientmgr_t *manager) { +#if NMCTXS > 0 + int i; +#endif + + REQUIRE(ISC_LIST_EMPTY(manager->active)); + REQUIRE(ISC_LIST_EMPTY(manager->inactive)); + REQUIRE(ISC_LIST_EMPTY(manager->recursing)); + + MTRACE("clientmgr_destroy"); + +#if NMCTXS > 0 + for (i = 0; i < NMCTXS; i++) { + if (manager->mctxpool[i] != NULL) + isc_mem_detach(&manager->mctxpool[i]); + } +#endif + + DESTROYLOCK(&manager->lock); + manager->magic = 0; + isc_mem_put(manager->mctx, manager, sizeof(*manager)); +} + +isc_result_t +ns_clientmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, + isc_timermgr_t *timermgr, ns_clientmgr_t **managerp) +{ + ns_clientmgr_t *manager; + isc_result_t result; +#if NMCTXS > 0 + int i; +#endif + + manager = isc_mem_get(mctx, sizeof(*manager)); + if (manager == NULL) + return (ISC_R_NOMEMORY); + + result = isc_mutex_init(&manager->lock); + if (result != ISC_R_SUCCESS) + goto cleanup_manager; + + manager->mctx = mctx; + manager->taskmgr = taskmgr; + manager->timermgr = timermgr; + manager->exiting = ISC_FALSE; + ISC_LIST_INIT(manager->active); + ISC_LIST_INIT(manager->inactive); + ISC_LIST_INIT(manager->recursing); +#if NMCTXS > 0 + manager->nextmctx = 0; + for (i = 0; i < NMCTXS; i++) + manager->mctxpool[i] = NULL; /* will be created on-demand */ +#endif + manager->magic = MANAGER_MAGIC; + + MTRACE("create"); + + *managerp = manager; + + return (ISC_R_SUCCESS); + + cleanup_manager: + isc_mem_put(manager->mctx, manager, sizeof(*manager)); + + return (result); +} + +void +ns_clientmgr_destroy(ns_clientmgr_t **managerp) { + ns_clientmgr_t *manager; + ns_client_t *client; + isc_boolean_t need_destroy = ISC_FALSE; + + REQUIRE(managerp != NULL); + manager = *managerp; + REQUIRE(VALID_MANAGER(manager)); + + MTRACE("destroy"); + + LOCK(&manager->lock); + + manager->exiting = ISC_TRUE; + + for (client = ISC_LIST_HEAD(manager->recursing); + client != NULL; + client = ISC_LIST_NEXT(client, link)) + isc_task_shutdown(client->task); + + for (client = ISC_LIST_HEAD(manager->active); + client != NULL; + client = ISC_LIST_NEXT(client, link)) + isc_task_shutdown(client->task); + + for (client = ISC_LIST_HEAD(manager->inactive); + client != NULL; + client = ISC_LIST_NEXT(client, link)) + isc_task_shutdown(client->task); + + if (ISC_LIST_EMPTY(manager->active) && + ISC_LIST_EMPTY(manager->inactive) && + ISC_LIST_EMPTY(manager->recursing)) + need_destroy = ISC_TRUE; + + UNLOCK(&manager->lock); + + if (need_destroy) + clientmgr_destroy(manager); + + *managerp = NULL; +} + +isc_result_t +ns_clientmgr_createclients(ns_clientmgr_t *manager, unsigned int n, + ns_interface_t *ifp, isc_boolean_t tcp) +{ + isc_result_t result = ISC_R_SUCCESS; + unsigned int i; + ns_client_t *client; + + REQUIRE(VALID_MANAGER(manager)); + REQUIRE(n > 0); + + MTRACE("createclients"); + + /* + * We MUST lock the manager lock for the entire client creation + * process. If we didn't do this, then a client could get a + * shutdown event and disappear out from under us. + */ + + LOCK(&manager->lock); + + for (i = 0; i < n; i++) { + isc_event_t *ev; + /* + * Allocate a client. First try to get a recycled one; + * if that fails, make a new one. + */ + client = ISC_LIST_HEAD(manager->inactive); + if (client != NULL) { + MTRACE("recycle"); + ISC_LIST_UNLINK(manager->inactive, client, link); + client->list = NULL; + } else { + MTRACE("create new"); + result = client_create(manager, &client); + if (result != ISC_R_SUCCESS) + break; + } + + ns_interface_attach(ifp, &client->interface); + client->state = NS_CLIENTSTATE_READY; + INSIST(client->recursionquota == NULL); + + if (tcp) { + client->attributes |= NS_CLIENTATTR_TCP; + isc_socket_attach(ifp->tcpsocket, + &client->tcplistener); + } else { + isc_socket_t *sock; + + dns_dispatch_attach(ifp->udpdispatch, + &client->dispatch); + sock = dns_dispatch_getsocket(client->dispatch); + isc_socket_attach(sock, &client->udpsocket); + } + client->manager = manager; + ISC_LIST_APPEND(manager->active, client, link); + client->list = &manager->active; + + INSIST(client->nctls == 0); + client->nctls++; + ev = &client->ctlevent; + isc_task_send(client->task, &ev); + } + if (i != 0) { + /* + * We managed to create at least one client, so we + * declare victory. + */ + result = ISC_R_SUCCESS; + } + + UNLOCK(&manager->lock); + + return (result); +} + +isc_sockaddr_t * +ns_client_getsockaddr(ns_client_t *client) { + return (&client->peeraddr); +} + +isc_result_t +ns_client_checkaclsilent(ns_client_t *client, isc_sockaddr_t *sockaddr, + dns_acl_t *acl, isc_boolean_t default_allow) +{ + isc_result_t result; + int match; + isc_netaddr_t netaddr; + + if (acl == NULL) { + if (default_allow) + goto allow; + else + goto deny; + } + + + if (sockaddr == NULL) + isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); + else + isc_netaddr_fromsockaddr(&netaddr, sockaddr); + + result = dns_acl_match(&netaddr, client->signer, acl, + &ns_g_server->aclenv, + &match, NULL); + + if (result != ISC_R_SUCCESS) + goto deny; /* Internal error, already logged. */ + if (match > 0) + goto allow; + goto deny; /* Negative match or no match. */ + + allow: + return (ISC_R_SUCCESS); + + deny: + return (DNS_R_REFUSED); +} + +isc_result_t +ns_client_checkacl(ns_client_t *client, isc_sockaddr_t *sockaddr, + const char *opname, dns_acl_t *acl, + isc_boolean_t default_allow, int log_level) +{ + isc_result_t result = + ns_client_checkaclsilent(client, sockaddr, acl, default_allow); + + if (result == ISC_R_SUCCESS) + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), + "%s approved", opname); + else + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, + log_level, "%s denied", opname); + return (result); +} + +static void +ns_client_name(ns_client_t *client, char *peerbuf, size_t len) { + if (client->peeraddr_valid) + isc_sockaddr_format(&client->peeraddr, peerbuf, len); + else + snprintf(peerbuf, len, "@%p", client); +} + +void +ns_client_logv(ns_client_t *client, isc_logcategory_t *category, + isc_logmodule_t *module, int level, const char *fmt, va_list ap) +{ + char msgbuf[2048]; + char peerbuf[ISC_SOCKADDR_FORMATSIZE]; + const char *name = ""; + const char *sep = ""; + + vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); + ns_client_name(client, peerbuf, sizeof(peerbuf)); + if (client->view != NULL && strcmp(client->view->name, "_bind") != 0 && + strcmp(client->view->name, "_default") != 0) { + name = client->view->name; + sep = ": view "; + } + + isc_log_write(ns_g_lctx, category, module, level, + "client %s%s%s: %s", peerbuf, sep, name, msgbuf); +} + +void +ns_client_log(ns_client_t *client, isc_logcategory_t *category, + isc_logmodule_t *module, int level, const char *fmt, ...) +{ + va_list ap; + + if (! isc_log_wouldlog(ns_g_lctx, level)) + return; + + va_start(ap, fmt); + ns_client_logv(client, category, module, level, fmt, ap); + va_end(ap); +} + +void +ns_client_aclmsg(const char *msg, dns_name_t *name, dns_rdatatype_t type, + dns_rdataclass_t rdclass, char *buf, size_t len) +{ + char namebuf[DNS_NAME_FORMATSIZE]; + char typebuf[DNS_RDATATYPE_FORMATSIZE]; + char classbuf[DNS_RDATACLASS_FORMATSIZE]; + + dns_name_format(name, namebuf, sizeof(namebuf)); + dns_rdatatype_format(type, typebuf, sizeof(typebuf)); + dns_rdataclass_format(rdclass, classbuf, sizeof(classbuf)); + (void)snprintf(buf, len, "%s '%s/%s/%s'", msg, namebuf, typebuf, + classbuf); +} + +static void +ns_client_dumpmessage(ns_client_t *client, const char *reason) { + isc_buffer_t buffer; + char *buf = NULL; + int len = 1024; + isc_result_t result; + + /* + * Note that these are multiline debug messages. We want a newline + * to appear in the log after each message. + */ + + do { + buf = isc_mem_get(client->mctx, len); + if (buf == NULL) + break; + isc_buffer_init(&buffer, buf, len); + result = dns_message_totext(client->message, + &dns_master_style_debug, + 0, &buffer); + if (result == ISC_R_NOSPACE) { + isc_mem_put(client->mctx, buf, len); + len += 1024; + } else if (result == ISC_R_SUCCESS) + ns_client_log(client, NS_LOGCATEGORY_UNMATCHED, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1), + "%s\n%.*s", reason, + (int)isc_buffer_usedlength(&buffer), + buf); + } while (result == ISC_R_NOSPACE); + + if (buf != NULL) + isc_mem_put(client->mctx, buf, len); +} + +void +ns_client_dumprecursing(FILE *f, ns_clientmgr_t *manager) { + ns_client_t *client; + char namebuf[DNS_NAME_FORMATSIZE]; + char peerbuf[ISC_SOCKADDR_FORMATSIZE]; + const char *name; + const char *sep; + + REQUIRE(VALID_MANAGER(manager)); + + LOCK(&manager->lock); + client = ISC_LIST_HEAD(manager->recursing); + while (client != NULL) { + ns_client_name(client, peerbuf, sizeof(peerbuf)); + if (client->view != NULL && + strcmp(client->view->name, "_bind") != 0 && + strcmp(client->view->name, "_default") != 0) { + name = client->view->name; + sep = ": view "; + } else { + name = ""; + sep = ""; + } + dns_name_format(client->query.qname, namebuf, sizeof(namebuf)); + fprintf(f, "; client %s%s%s: '%s' requesttime %d\n", + peerbuf, sep, name, namebuf, client->requesttime); + client = ISC_LIST_NEXT(client, link); + } + UNLOCK(&manager->lock); +} + +void +ns_client_qnamereplace(ns_client_t *client, dns_name_t *name) { + + if (client->manager != NULL) + LOCK(&client->manager->lock); + if (client->query.restarts > 0) { + /* + * client->query.qname was dynamically allocated. + */ + dns_message_puttempname(client->message, + &client->query.qname); + } + client->query.qname = name; + if (client->manager != NULL) + UNLOCK(&client->manager->lock); +} diff --git a/contrib/bind-9.5.2/bin/named/config.c b/contrib/bind-9.5.2/bin/named/config.c new file mode 100644 index 0000000000..6ac2d1a32a --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/config.c @@ -0,0 +1,803 @@ +/* + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001-2003 Internet Software Consortium. + * + * 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: config.c,v 1.82.38.8 2008/09/27 23:39:42 jinmei Exp $ */ + +/*! \file */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +/*% default configuration */ +static char defaultconf[] = "\ +options {\n\ +# blackhole {none;};\n" +#ifndef WIN32 +" coresize default;\n\ + datasize default;\n\ + files unlimited;\n\ + stacksize default;\n" +#endif +" deallocate-on-exit true;\n\ +# directory \n\ + dump-file \"named_dump.db\";\n\ + fake-iquery no;\n\ + has-old-clients false;\n\ + heartbeat-interval 60;\n\ + host-statistics no;\n\ + interface-interval 60;\n\ + listen-on {any;};\n\ + listen-on-v6 {none;};\n\ + match-mapped-addresses no;\n\ + memstatistics-file \"named.memstats\";\n\ + multiple-cnames no;\n\ +# named-xfer ;\n\ +# pid-file \"" NS_LOCALSTATEDIR "/named.pid\"; /* or /lwresd.pid */\n\ + port 53;\n\ + recursing-file \"named.recursing\";\n\ +" +#ifdef PATH_RANDOMDEV +"\ + random-device \"" PATH_RANDOMDEV "\";\n\ +" +#endif +"\ + recursive-clients 1000;\n\ + rrset-order {type NS order random; order cyclic; };\n\ + serial-queries 20;\n\ + serial-query-rate 20;\n\ + server-id none;\n\ + statistics-file \"named.stats\";\n\ + statistics-interval 60;\n\ + tcp-clients 100;\n\ + tcp-listen-queue 3;\n\ +# tkey-dhkey \n\ +# tkey-gssapi-credential \n\ +# tkey-domain \n\ + transfers-per-ns 2;\n\ + transfers-in 10;\n\ + transfers-out 10;\n\ + treat-cr-as-space true;\n\ + use-id-pool true;\n\ + use-ixfr true;\n\ + edns-udp-size 4096;\n\ + max-udp-size 4096;\n\ + request-nsid false;\n\ + reserved-sockets 512;\n\ +\n\ + /* view */\n\ + allow-notify {none;};\n\ + allow-update-forwarding {none;};\n\ + allow-query-cache { localnets; localhost; };\n\ + allow-query-cache-on { any; };\n\ + allow-recursion { localnets; localhost; };\n\ + allow-recursion-on { any; };\n\ +# allow-v6-synthesis ;\n\ +# sortlist \n\ +# topology \n\ + auth-nxdomain false;\n\ + minimal-responses false;\n\ + recursion true;\n\ + provide-ixfr true;\n\ + request-ixfr true;\n\ + fetch-glue no;\n\ + rfc2308-type1 no;\n\ + additional-from-auth true;\n\ + additional-from-cache true;\n\ + query-source address *;\n\ + query-source-v6 address *;\n\ + notify-source *;\n\ + notify-source-v6 *;\n\ + cleaning-interval 0; /* now meaningless */\n\ + min-roots 2;\n\ + lame-ttl 600;\n\ + max-ncache-ttl 10800; /* 3 hours */\n\ + max-cache-ttl 604800; /* 1 week */\n\ + transfer-format many-answers;\n\ + max-cache-size 0;\n\ + check-names master fail;\n\ + check-names slave warn;\n\ + check-names response ignore;\n\ + check-mx warn;\n\ + acache-enable no;\n\ + acache-cleaning-interval 60;\n\ + max-acache-size 16M;\n\ + dnssec-enable yes;\n\ + dnssec-validation yes; \n\ + dnssec-accept-expired no;\n\ + clients-per-query 10;\n\ + max-clients-per-query 100;\n\ + zero-no-soa-ttl-cache no;\n\ +" + +" /* zone */\n\ + allow-query {any;};\n\ + allow-query-on {any;};\n\ + allow-transfer {any;};\n\ + notify yes;\n\ +# also-notify \n\ + notify-delay 5;\n\ + notify-to-soa no;\n\ + dialup no;\n\ +# forward \n\ +# forwarders \n\ + maintain-ixfr-base no;\n\ +# max-ixfr-log-size \n\ + transfer-source *;\n\ + transfer-source-v6 *;\n\ + alt-transfer-source *;\n\ + alt-transfer-source-v6 *;\n\ + max-transfer-time-in 120;\n\ + max-transfer-time-out 120;\n\ + max-transfer-idle-in 60;\n\ + max-transfer-idle-out 60;\n\ + max-retry-time 1209600; /* 2 weeks */\n\ + min-retry-time 500;\n\ + max-refresh-time 2419200; /* 4 weeks */\n\ + min-refresh-time 300;\n\ + multi-master no;\n\ + sig-validity-interval 30; /* days */\n\ + zone-statistics false;\n\ + max-journal-size unlimited;\n\ + ixfr-from-differences false;\n\ + check-wildcard yes;\n\ + check-sibling yes;\n\ + check-integrity yes;\n\ + check-mx-cname warn;\n\ + check-srv-cname warn;\n\ + zero-no-soa-ttl yes;\n\ + update-check-ksk yes;\n\ + try-tcp-refresh yes; /* BIND 8 compat */\n\ +};\n\ +" + +"#\n\ +# Zones in the \"_bind\" view are NOT counted in the count of zones.\n\ +#\n\ +view \"_bind\" chaos {\n\ + recursion no;\n\ + notify no;\n\ +\n\ + zone \"version.bind\" chaos {\n\ + type master;\n\ + database \"_builtin version\";\n\ + };\n\ +\n\ + zone \"hostname.bind\" chaos {\n\ + type master;\n\ + database \"_builtin hostname\";\n\ + };\n\ +\n\ + zone \"authors.bind\" chaos {\n\ + type master;\n\ + database \"_builtin authors\";\n\ + };\n\ + zone \"id.server\" chaos {\n\ + type master;\n\ + database \"_builtin id\";\n\ + };\n\ +};\n\ +"; + +isc_result_t +ns_config_parsedefaults(cfg_parser_t *parser, cfg_obj_t **conf) { + isc_buffer_t b; + + isc_buffer_init(&b, defaultconf, sizeof(defaultconf) - 1); + isc_buffer_add(&b, sizeof(defaultconf) - 1); + return (cfg_parse_buffer(parser, &b, &cfg_type_namedconf, conf)); +} + +isc_result_t +ns_config_get(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) { + int i; + + for (i = 0;; i++) { + if (maps[i] == NULL) + return (ISC_R_NOTFOUND); + if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS) + return (ISC_R_SUCCESS); + } +} + +isc_result_t +ns_checknames_get(const cfg_obj_t **maps, const char *which, + const cfg_obj_t **obj) +{ + const cfg_listelt_t *element; + const cfg_obj_t *checknames; + const cfg_obj_t *type; + const cfg_obj_t *value; + int i; + + for (i = 0;; i++) { + if (maps[i] == NULL) + return (ISC_R_NOTFOUND); + checknames = NULL; + if (cfg_map_get(maps[i], "check-names", &checknames) == ISC_R_SUCCESS) { + /* + * Zone map entry is not a list. + */ + if (checknames != NULL && !cfg_obj_islist(checknames)) { + *obj = checknames; + return (ISC_R_SUCCESS); + } + for (element = cfg_list_first(checknames); + element != NULL; + element = cfg_list_next(element)) { + value = cfg_listelt_value(element); + type = cfg_tuple_get(value, "type"); + if (strcasecmp(cfg_obj_asstring(type), which) == 0) { + *obj = cfg_tuple_get(value, "mode"); + return (ISC_R_SUCCESS); + } + } + + } + } +} + +int +ns_config_listcount(const cfg_obj_t *list) { + const cfg_listelt_t *e; + int i = 0; + + for (e = cfg_list_first(list); e != NULL; e = cfg_list_next(e)) + i++; + + return (i); +} + +isc_result_t +ns_config_getclass(const cfg_obj_t *classobj, dns_rdataclass_t defclass, + dns_rdataclass_t *classp) { + isc_textregion_t r; + isc_result_t result; + + if (!cfg_obj_isstring(classobj)) { + *classp = defclass; + return (ISC_R_SUCCESS); + } + DE_CONST(cfg_obj_asstring(classobj), r.base); + r.length = strlen(r.base); + result = dns_rdataclass_fromtext(classp, &r); + if (result != ISC_R_SUCCESS) + cfg_obj_log(classobj, ns_g_lctx, ISC_LOG_ERROR, + "unknown class '%s'", r.base); + return (result); +} + +isc_result_t +ns_config_gettype(const cfg_obj_t *typeobj, dns_rdatatype_t deftype, + dns_rdatatype_t *typep) { + isc_textregion_t r; + isc_result_t result; + + if (!cfg_obj_isstring(typeobj)) { + *typep = deftype; + return (ISC_R_SUCCESS); + } + DE_CONST(cfg_obj_asstring(typeobj), r.base); + r.length = strlen(r.base); + result = dns_rdatatype_fromtext(typep, &r); + if (result != ISC_R_SUCCESS) + cfg_obj_log(typeobj, ns_g_lctx, ISC_LOG_ERROR, + "unknown type '%s'", r.base); + return (result); +} + +dns_zonetype_t +ns_config_getzonetype(const cfg_obj_t *zonetypeobj) { + dns_zonetype_t ztype = dns_zone_none; + const char *str; + + str = cfg_obj_asstring(zonetypeobj); + if (strcasecmp(str, "master") == 0) + ztype = dns_zone_master; + else if (strcasecmp(str, "slave") == 0) + ztype = dns_zone_slave; + else if (strcasecmp(str, "stub") == 0) + ztype = dns_zone_stub; + else + INSIST(0); + return (ztype); +} + +isc_result_t +ns_config_getiplist(const cfg_obj_t *config, const cfg_obj_t *list, + in_port_t defport, isc_mem_t *mctx, + isc_sockaddr_t **addrsp, isc_uint32_t *countp) +{ + int count, i = 0; + const cfg_obj_t *addrlist; + const cfg_obj_t *portobj; + const cfg_listelt_t *element; + isc_sockaddr_t *addrs; + in_port_t port; + isc_result_t result; + + INSIST(addrsp != NULL && *addrsp == NULL); + INSIST(countp != NULL); + + addrlist = cfg_tuple_get(list, "addresses"); + count = ns_config_listcount(addrlist); + + portobj = cfg_tuple_get(list, "port"); + if (cfg_obj_isuint32(portobj)) { + isc_uint32_t val = cfg_obj_asuint32(portobj); + if (val > ISC_UINT16_MAX) { + cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, + "port '%u' out of range", val); + return (ISC_R_RANGE); + } + port = (in_port_t) val; + } else if (defport != 0) + port = defport; + else { + result = ns_config_getport(config, &port); + if (result != ISC_R_SUCCESS) + return (result); + } + + addrs = isc_mem_get(mctx, count * sizeof(isc_sockaddr_t)); + if (addrs == NULL) + return (ISC_R_NOMEMORY); + + for (element = cfg_list_first(addrlist); + element != NULL; + element = cfg_list_next(element), i++) + { + INSIST(i < count); + addrs[i] = *cfg_obj_assockaddr(cfg_listelt_value(element)); + if (isc_sockaddr_getport(&addrs[i]) == 0) + isc_sockaddr_setport(&addrs[i], port); + } + INSIST(i == count); + + *addrsp = addrs; + *countp = count; + + return (ISC_R_SUCCESS); +} + +void +ns_config_putiplist(isc_mem_t *mctx, isc_sockaddr_t **addrsp, + isc_uint32_t count) +{ + INSIST(addrsp != NULL && *addrsp != NULL); + + isc_mem_put(mctx, *addrsp, count * sizeof(isc_sockaddr_t)); + *addrsp = NULL; +} + +static isc_result_t +get_masters_def(const cfg_obj_t *cctx, const char *name, + const cfg_obj_t **ret) +{ + isc_result_t result; + const cfg_obj_t *masters = NULL; + const cfg_listelt_t *elt; + + result = cfg_map_get(cctx, "masters", &masters); + if (result != ISC_R_SUCCESS) + return (result); + for (elt = cfg_list_first(masters); + elt != NULL; + elt = cfg_list_next(elt)) { + const cfg_obj_t *list; + const char *listname; + + list = cfg_listelt_value(elt); + listname = cfg_obj_asstring(cfg_tuple_get(list, "name")); + + if (strcasecmp(listname, name) == 0) { + *ret = list; + return (ISC_R_SUCCESS); + } + } + return (ISC_R_NOTFOUND); +} + +isc_result_t +ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list, + isc_mem_t *mctx, isc_sockaddr_t **addrsp, + dns_name_t ***keysp, isc_uint32_t *countp) +{ + isc_uint32_t addrcount = 0, keycount = 0, i = 0; + isc_uint32_t listcount = 0, l = 0, j; + isc_uint32_t stackcount = 0, pushed = 0; + isc_result_t result; + const cfg_listelt_t *element; + const cfg_obj_t *addrlist; + const cfg_obj_t *portobj; + in_port_t port; + dns_fixedname_t fname; + isc_sockaddr_t *addrs = NULL; + dns_name_t **keys = NULL; + struct { const char *name; } *lists = NULL; + struct { + const cfg_listelt_t *element; + in_port_t port; + } *stack = NULL; + + REQUIRE(addrsp != NULL && *addrsp == NULL); + REQUIRE(keysp != NULL && *keysp == NULL); + REQUIRE(countp != NULL); + + newlist: + addrlist = cfg_tuple_get(list, "addresses"); + portobj = cfg_tuple_get(list, "port"); + if (cfg_obj_isuint32(portobj)) { + isc_uint32_t val = cfg_obj_asuint32(portobj); + if (val > ISC_UINT16_MAX) { + cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, + "port '%u' out of range", val); + result = ISC_R_RANGE; + goto cleanup; + } + port = (in_port_t) val; + } else { + result = ns_config_getport(config, &port); + if (result != ISC_R_SUCCESS) + goto cleanup; + } + + result = ISC_R_NOMEMORY; + + element = cfg_list_first(addrlist); + resume: + for ( ; + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *addr; + const cfg_obj_t *key; + const char *keystr; + isc_buffer_t b; + + addr = cfg_tuple_get(cfg_listelt_value(element), + "masterselement"); + key = cfg_tuple_get(cfg_listelt_value(element), "key"); + + if (!cfg_obj_issockaddr(addr)) { + const char *listname = cfg_obj_asstring(addr); + isc_result_t tresult; + + /* Grow lists? */ + if (listcount == l) { + void * new; + isc_uint32_t newlen = listcount + 16; + size_t newsize, oldsize; + + newsize = newlen * sizeof(*lists); + oldsize = listcount * sizeof(*lists); + new = isc_mem_get(mctx, newsize); + if (new == NULL) + goto cleanup; + if (listcount != 0) { + memcpy(new, lists, oldsize); + isc_mem_put(mctx, lists, oldsize); + } + lists = new; + listcount = newlen; + } + /* Seen? */ + for (j = 0; j < l; j++) + if (strcasecmp(lists[j].name, listname) == 0) + break; + if (j < l) + continue; + tresult = get_masters_def(config, listname, &list); + if (tresult == ISC_R_NOTFOUND) { + cfg_obj_log(addr, ns_g_lctx, ISC_LOG_ERROR, + "masters \"%s\" not found", listname); + + result = tresult; + goto cleanup; + } + if (tresult != ISC_R_SUCCESS) + goto cleanup; + lists[l++].name = listname; + /* Grow stack? */ + if (stackcount == pushed) { + void * new; + isc_uint32_t newlen = stackcount + 16; + size_t newsize, oldsize; + + newsize = newlen * sizeof(*stack); + oldsize = stackcount * sizeof(*stack); + new = isc_mem_get(mctx, newsize); + if (new == NULL) + goto cleanup; + if (stackcount != 0) { + memcpy(new, stack, oldsize); + isc_mem_put(mctx, stack, oldsize); + } + stack = new; + stackcount = newlen; + } + /* + * We want to resume processing this list on the + * next element. + */ + stack[pushed].element = cfg_list_next(element); + stack[pushed].port = port; + pushed++; + goto newlist; + } + + if (i == addrcount) { + void * new; + isc_uint32_t newlen = addrcount + 16; + size_t newsize, oldsize; + + newsize = newlen * sizeof(isc_sockaddr_t); + oldsize = addrcount * sizeof(isc_sockaddr_t); + new = isc_mem_get(mctx, newsize); + if (new == NULL) + goto cleanup; + if (addrcount != 0) { + memcpy(new, addrs, oldsize); + isc_mem_put(mctx, addrs, oldsize); + } + addrs = new; + addrcount = newlen; + + newsize = newlen * sizeof(dns_name_t *); + oldsize = keycount * sizeof(dns_name_t *); + new = isc_mem_get(mctx, newsize); + if (new == NULL) + goto cleanup; + if (keycount != 0) { + memcpy(new, keys, oldsize); + isc_mem_put(mctx, keys, oldsize); + } + keys = new; + keycount = newlen; + } + + addrs[i] = *cfg_obj_assockaddr(addr); + if (isc_sockaddr_getport(&addrs[i]) == 0) + isc_sockaddr_setport(&addrs[i], port); + keys[i] = NULL; + if (!cfg_obj_isstring(key)) { + i++; + continue; + } + keys[i] = isc_mem_get(mctx, sizeof(dns_name_t)); + if (keys[i] == NULL) + goto cleanup; + dns_name_init(keys[i], NULL); + + keystr = cfg_obj_asstring(key); + isc_buffer_init(&b, keystr, strlen(keystr)); + isc_buffer_add(&b, strlen(keystr)); + dns_fixedname_init(&fname); + result = dns_name_fromtext(dns_fixedname_name(&fname), &b, + dns_rootname, ISC_FALSE, NULL); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_name_dup(dns_fixedname_name(&fname), mctx, + keys[i]); + if (result != ISC_R_SUCCESS) + goto cleanup; + i++; + } + if (pushed != 0) { + pushed--; + element = stack[pushed].element; + port = stack[pushed].port; + goto resume; + } + if (i < addrcount) { + void * new; + size_t newsize, oldsize; + + newsize = i * sizeof(isc_sockaddr_t); + oldsize = addrcount * sizeof(isc_sockaddr_t); + if (i != 0) { + new = isc_mem_get(mctx, newsize); + if (new == NULL) + goto cleanup; + memcpy(new, addrs, newsize); + } else + new = NULL; + isc_mem_put(mctx, addrs, oldsize); + addrs = new; + addrcount = i; + + newsize = i * sizeof(dns_name_t *); + oldsize = keycount * sizeof(dns_name_t *); + if (i != 0) { + new = isc_mem_get(mctx, newsize); + if (new == NULL) + goto cleanup; + memcpy(new, keys, newsize); + } else + new = NULL; + isc_mem_put(mctx, keys, oldsize); + keys = new; + keycount = i; + } + + if (lists != NULL) + isc_mem_put(mctx, lists, listcount * sizeof(*lists)); + if (stack != NULL) + isc_mem_put(mctx, stack, stackcount * sizeof(*stack)); + + INSIST(keycount == addrcount); + + *addrsp = addrs; + *keysp = keys; + *countp = addrcount; + + return (ISC_R_SUCCESS); + + cleanup: + if (addrs != NULL) + isc_mem_put(mctx, addrs, addrcount * sizeof(isc_sockaddr_t)); + if (keys != NULL) { + for (j = 0; j <= i; j++) { + if (keys[j] == NULL) + continue; + if (dns_name_dynamic(keys[j])) + dns_name_free(keys[j], mctx); + isc_mem_put(mctx, keys[j], sizeof(dns_name_t)); + } + isc_mem_put(mctx, keys, keycount * sizeof(dns_name_t *)); + } + if (lists != NULL) + isc_mem_put(mctx, lists, listcount * sizeof(*lists)); + if (stack != NULL) + isc_mem_put(mctx, stack, stackcount * sizeof(*stack)); + return (result); +} + +void +ns_config_putipandkeylist(isc_mem_t *mctx, isc_sockaddr_t **addrsp, + dns_name_t ***keysp, isc_uint32_t count) +{ + unsigned int i; + dns_name_t **keys = *keysp; + + INSIST(addrsp != NULL && *addrsp != NULL); + + isc_mem_put(mctx, *addrsp, count * sizeof(isc_sockaddr_t)); + for (i = 0; i < count; i++) { + if (keys[i] == NULL) + continue; + if (dns_name_dynamic(keys[i])) + dns_name_free(keys[i], mctx); + isc_mem_put(mctx, keys[i], sizeof(dns_name_t)); + } + isc_mem_put(mctx, *keysp, count * sizeof(dns_name_t *)); + *addrsp = NULL; + *keysp = NULL; +} + +isc_result_t +ns_config_getport(const cfg_obj_t *config, in_port_t *portp) { + const cfg_obj_t *maps[3]; + const cfg_obj_t *options = NULL; + const cfg_obj_t *portobj = NULL; + isc_result_t result; + int i; + + (void)cfg_map_get(config, "options", &options); + i = 0; + if (options != NULL) + maps[i++] = options; + maps[i++] = ns_g_defaults; + maps[i] = NULL; + + result = ns_config_get(maps, "port", &portobj); + INSIST(result == ISC_R_SUCCESS); + if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) { + cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, + "port '%u' out of range", + cfg_obj_asuint32(portobj)); + return (ISC_R_RANGE); + } + *portp = (in_port_t)cfg_obj_asuint32(portobj); + return (ISC_R_SUCCESS); +} + +struct keyalgorithms { + const char *str; + enum { hmacnone, hmacmd5, hmacsha1, hmacsha224, + hmacsha256, hmacsha384, hmacsha512 } hmac; + isc_uint16_t size; +} algorithms[] = { + { "hmac-md5", hmacmd5, 128 }, + { "hmac-md5.sig-alg.reg.int", hmacmd5, 0 }, + { "hmac-md5.sig-alg.reg.int.", hmacmd5, 0 }, + { "hmac-sha1", hmacsha1, 160 }, + { "hmac-sha224", hmacsha224, 224 }, + { "hmac-sha256", hmacsha256, 256 }, + { "hmac-sha384", hmacsha384, 384 }, + { "hmac-sha512", hmacsha512, 512 }, + { NULL, hmacnone, 0 } +}; + +isc_result_t +ns_config_getkeyalgorithm(const char *str, dns_name_t **name, + isc_uint16_t *digestbits) +{ + int i; + size_t len = 0; + isc_uint16_t bits; + isc_result_t result; + + for (i = 0; algorithms[i].str != NULL; i++) { + len = strlen(algorithms[i].str); + if (strncasecmp(algorithms[i].str, str, len) == 0 && + (str[len] == '\0' || + (algorithms[i].size != 0 && str[len] == '-'))) + break; + } + if (algorithms[i].str == NULL) + return (ISC_R_NOTFOUND); + if (str[len] == '-') { + result = isc_parse_uint16(&bits, str + len + 1, 10); + if (result != ISC_R_SUCCESS) + return (result); + if (bits > algorithms[i].size) + return (ISC_R_RANGE); + } else if (algorithms[i].size == 0) + bits = 128; + else + bits = algorithms[i].size; + + if (name != NULL) { + switch (algorithms[i].hmac) { + case hmacmd5: *name = dns_tsig_hmacmd5_name; break; + case hmacsha1: *name = dns_tsig_hmacsha1_name; break; + case hmacsha224: *name = dns_tsig_hmacsha224_name; break; + case hmacsha256: *name = dns_tsig_hmacsha256_name; break; + case hmacsha384: *name = dns_tsig_hmacsha384_name; break; + case hmacsha512: *name = dns_tsig_hmacsha512_name; break; + default: + INSIST(0); + } + } + if (digestbits != NULL) + *digestbits = bits; + return (ISC_R_SUCCESS); +} diff --git a/contrib/bind-9.5.2/bin/named/control.c b/contrib/bind-9.5.2/bin/named/control.c new file mode 100644 index 0000000000..ca9f7f7d7d --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/control.c @@ -0,0 +1,199 @@ +/* + * 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 + * 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: control.c,v 1.33.62.2 2009/07/11 23:46:45 tbox Exp $ */ + +/*! \file */ + +#include + + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#ifdef HAVE_LIBSCF +#include +#endif + +static isc_boolean_t +command_compare(const char *text, const char *command) { + unsigned int commandlen = strlen(command); + if (strncasecmp(text, command, commandlen) == 0 && + (text[commandlen] == '\0' || + text[commandlen] == ' ' || + text[commandlen] == '\t')) + return (ISC_TRUE); + return (ISC_FALSE); +} + +/*% + * This function is called to process the incoming command + * when a control channel message is received. + */ +isc_result_t +ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text) { + isccc_sexpr_t *data; + char *command; + isc_result_t result; + int log_level; +#ifdef HAVE_LIBSCF + ns_smf_want_disable = 0; +#endif + + data = isccc_alist_lookup(message, "_data"); + if (data == NULL) { + /* + * No data section. + */ + return (ISC_R_FAILURE); + } + + result = isccc_cc_lookupstring(data, "type", &command); + if (result != ISC_R_SUCCESS) { + /* + * We have no idea what this is. + */ + return (result); + } + + /* + * Compare the 'command' parameter against all known control commands. + */ + if (command_compare(command, NS_COMMAND_NULL) || + command_compare(command, NS_COMMAND_STATUS)) { + log_level = ISC_LOG_DEBUG(1); + } else { + log_level = ISC_LOG_INFO; + } + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_CONTROL, log_level, + "received control channel command '%s'", + command); + + if (command_compare(command, NS_COMMAND_RELOAD)) { + result = ns_server_reloadcommand(ns_g_server, command, text); + } else if (command_compare(command, NS_COMMAND_RECONFIG)) { + result = ns_server_reconfigcommand(ns_g_server, command); + } else if (command_compare(command, NS_COMMAND_REFRESH)) { + result = ns_server_refreshcommand(ns_g_server, command, text); + } else if (command_compare(command, NS_COMMAND_RETRANSFER)) { + result = ns_server_retransfercommand(ns_g_server, command); + } else if (command_compare(command, NS_COMMAND_HALT)) { +#ifdef HAVE_LIBSCF + /* + * If we are managed by smf(5), AND in chroot, then + * we cannot connect to the smf repository, so just + * return with an appropriate message back to rndc. + */ + if (ns_smf_got_instance == 1 && ns_smf_chroot == 1) { + result = ns_smf_add_message(text); + return (result); + } + /* + * If we are managed by smf(5) but not in chroot, + * try to disable ourselves the smf way. + */ + if (ns_smf_got_instance == 1 && ns_smf_chroot == 0) + ns_smf_want_disable = 1; + /* + * If ns_smf_got_instance = 0, ns_smf_chroot + * is not relevant and we fall through to + * isc_app_shutdown below. + */ +#endif + ns_server_flushonshutdown(ns_g_server, ISC_FALSE); + ns_os_shutdownmsg(command, text); + isc_app_shutdown(); + result = ISC_R_SUCCESS; + } else if (command_compare(command, NS_COMMAND_STOP)) { +#ifdef HAVE_LIBSCF + if (ns_smf_got_instance == 1 && ns_smf_chroot == 1) { + result = ns_smf_add_message(text); + return (result); + } + if (ns_smf_got_instance == 1 && ns_smf_chroot == 0) + ns_smf_want_disable = 1; +#endif + ns_server_flushonshutdown(ns_g_server, ISC_TRUE); + ns_os_shutdownmsg(command, text); + isc_app_shutdown(); + result = ISC_R_SUCCESS; + } else if (command_compare(command, NS_COMMAND_DUMPSTATS)) { + result = ns_server_dumpstats(ns_g_server); + } else if (command_compare(command, NS_COMMAND_QUERYLOG)) { + result = ns_server_togglequerylog(ns_g_server); + } else if (command_compare(command, NS_COMMAND_DUMPDB)) { + ns_server_dumpdb(ns_g_server, command); + result = ISC_R_SUCCESS; + } else if (command_compare(command, NS_COMMAND_TRACE)) { + result = ns_server_setdebuglevel(ns_g_server, command); + } else if (command_compare(command, NS_COMMAND_NOTRACE)) { + ns_g_debuglevel = 0; + isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel); + result = ISC_R_SUCCESS; + } else if (command_compare(command, NS_COMMAND_FLUSH)) { + result = ns_server_flushcache(ns_g_server, command); + } else if (command_compare(command, NS_COMMAND_FLUSHNAME)) { + result = ns_server_flushname(ns_g_server, command); + } else if (command_compare(command, NS_COMMAND_STATUS)) { + result = ns_server_status(ns_g_server, text); + } else if (command_compare(command, NS_COMMAND_TSIGLIST)) { + result = ns_server_tsiglist(ns_g_server, text); + } else if (command_compare(command, NS_COMMAND_TSIGDELETE)) { + result = ns_server_tsigdelete(ns_g_server, command, text); + } else if (command_compare(command, NS_COMMAND_FREEZE)) { + result = ns_server_freeze(ns_g_server, ISC_TRUE, command, + text); + } else if (command_compare(command, NS_COMMAND_UNFREEZE) || + command_compare(command, NS_COMMAND_THAW)) { + result = ns_server_freeze(ns_g_server, ISC_FALSE, command, + text); + } else if (command_compare(command, NS_COMMAND_RECURSING)) { + result = ns_server_dumprecursing(ns_g_server); + } else if (command_compare(command, NS_COMMAND_TIMERPOKE)) { + result = ISC_R_SUCCESS; + isc_timermgr_poke(ns_g_timermgr); + } else if (command_compare(command, NS_COMMAND_NULL)) { + result = ISC_R_SUCCESS; + } else if (command_compare(command, NS_COMMAND_NOTIFY)) { + result = ns_server_notifycommand(ns_g_server, command, text); + } else if (command_compare(command, NS_COMMAND_VALIDATION)) { + result = ns_server_validation(ns_g_server, command); + } else { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, + "unknown control channel command '%s'", + command); + result = DNS_R_UNKNOWNCOMMAND; + } + + return (result); +} diff --git a/contrib/bind-9.5.2/bin/named/controlconf.c b/contrib/bind-9.5.2/bin/named/controlconf.c new file mode 100644 index 0000000000..b9af98c8a4 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/controlconf.c @@ -0,0 +1,1459 @@ +/* + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001-2003 Internet Software Consortium. + * + * 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: controlconf.c,v 1.55.64.4 2008/07/23 23:31:17 marka Exp $ */ + +/*! \file */ + +#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 + +/* + * Note: Listeners and connections are not locked. All event handlers are + * executed by the server task, and all callers of exported routines must + * be running under the server task. + */ + +typedef struct controlkey controlkey_t; +typedef ISC_LIST(controlkey_t) controlkeylist_t; + +typedef struct controlconnection controlconnection_t; +typedef ISC_LIST(controlconnection_t) controlconnectionlist_t; + +typedef struct controllistener controllistener_t; +typedef ISC_LIST(controllistener_t) controllistenerlist_t; + +struct controlkey { + char * keyname; + isc_region_t secret; + ISC_LINK(controlkey_t) link; +}; + +struct controlconnection { + isc_socket_t * sock; + isccc_ccmsg_t ccmsg; + isc_boolean_t ccmsg_valid; + isc_boolean_t sending; + isc_timer_t * timer; + unsigned char buffer[2048]; + controllistener_t * listener; + isc_uint32_t nonce; + ISC_LINK(controlconnection_t) link; +}; + +struct controllistener { + ns_controls_t * controls; + isc_mem_t * mctx; + isc_task_t * task; + isc_sockaddr_t address; + isc_socket_t * sock; + dns_acl_t * acl; + isc_boolean_t listening; + isc_boolean_t exiting; + controlkeylist_t keys; + controlconnectionlist_t connections; + isc_sockettype_t type; + isc_uint32_t perm; + isc_uint32_t owner; + isc_uint32_t group; + ISC_LINK(controllistener_t) link; +}; + +struct ns_controls { + ns_server_t *server; + controllistenerlist_t listeners; + isc_boolean_t shuttingdown; + isccc_symtab_t *symtab; +}; + +static void control_newconn(isc_task_t *task, isc_event_t *event); +static void control_recvmessage(isc_task_t *task, isc_event_t *event); + +#define CLOCKSKEW 300 + +static void +free_controlkey(controlkey_t *key, isc_mem_t *mctx) { + if (key->keyname != NULL) + isc_mem_free(mctx, key->keyname); + if (key->secret.base != NULL) + isc_mem_put(mctx, key->secret.base, key->secret.length); + isc_mem_put(mctx, key, sizeof(*key)); +} + +static void +free_controlkeylist(controlkeylist_t *keylist, isc_mem_t *mctx) { + while (!ISC_LIST_EMPTY(*keylist)) { + controlkey_t *key = ISC_LIST_HEAD(*keylist); + ISC_LIST_UNLINK(*keylist, key, link); + free_controlkey(key, mctx); + } +} + +static void +free_listener(controllistener_t *listener) { + INSIST(listener->exiting); + INSIST(!listener->listening); + INSIST(ISC_LIST_EMPTY(listener->connections)); + + if (listener->sock != NULL) + isc_socket_detach(&listener->sock); + + free_controlkeylist(&listener->keys, listener->mctx); + + if (listener->acl != NULL) + dns_acl_detach(&listener->acl); + + isc_mem_put(listener->mctx, listener, sizeof(*listener)); +} + +static void +maybe_free_listener(controllistener_t *listener) { + if (listener->exiting && + !listener->listening && + ISC_LIST_EMPTY(listener->connections)) + free_listener(listener); +} + +static void +maybe_free_connection(controlconnection_t *conn) { + controllistener_t *listener = conn->listener; + + if (conn->timer != NULL) + isc_timer_detach(&conn->timer); + + if (conn->ccmsg_valid) { + isccc_ccmsg_cancelread(&conn->ccmsg); + return; + } + + if (conn->sending) { + isc_socket_cancel(conn->sock, listener->task, + ISC_SOCKCANCEL_SEND); + return; + } + + ISC_LIST_UNLINK(listener->connections, conn, link); + isc_mem_put(listener->mctx, conn, sizeof(*conn)); +} + +static void +shutdown_listener(controllistener_t *listener) { + controlconnection_t *conn; + controlconnection_t *next; + + if (!listener->exiting) { + char socktext[ISC_SOCKADDR_FORMATSIZE]; + + ISC_LIST_UNLINK(listener->controls->listeners, listener, link); + + isc_sockaddr_format(&listener->address, socktext, + sizeof(socktext)); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE, + "stopping command channel on %s", socktext); + if (listener->type == isc_sockettype_unix) + isc_socket_cleanunix(&listener->address, ISC_TRUE); + listener->exiting = ISC_TRUE; + } + + for (conn = ISC_LIST_HEAD(listener->connections); + conn != NULL; + conn = next) + { + next = ISC_LIST_NEXT(conn, link); + maybe_free_connection(conn); + } + + if (listener->listening) + isc_socket_cancel(listener->sock, listener->task, + ISC_SOCKCANCEL_ACCEPT); + + maybe_free_listener(listener); +} + +static isc_boolean_t +address_ok(isc_sockaddr_t *sockaddr, dns_acl_t *acl) { + isc_netaddr_t netaddr; + isc_result_t result; + int match; + + isc_netaddr_fromsockaddr(&netaddr, sockaddr); + + result = dns_acl_match(&netaddr, NULL, acl, + &ns_g_server->aclenv, &match, NULL); + + if (result != ISC_R_SUCCESS || match <= 0) + return (ISC_FALSE); + else + return (ISC_TRUE); +} + +static isc_result_t +control_accept(controllistener_t *listener) { + isc_result_t result; + result = isc_socket_accept(listener->sock, + listener->task, + control_newconn, listener); + if (result != ISC_R_SUCCESS) + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_socket_accept() failed: %s", + isc_result_totext(result)); + else + listener->listening = ISC_TRUE; + return (result); +} + +static isc_result_t +control_listen(controllistener_t *listener) { + isc_result_t result; + + result = isc_socket_listen(listener->sock, 0); + if (result != ISC_R_SUCCESS) + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_socket_listen() failed: %s", + isc_result_totext(result)); + return (result); +} + +static void +control_next(controllistener_t *listener) { + (void)control_accept(listener); +} + +static void +control_senddone(isc_task_t *task, isc_event_t *event) { + isc_socketevent_t *sevent = (isc_socketevent_t *) event; + controlconnection_t *conn = event->ev_arg; + controllistener_t *listener = conn->listener; + isc_socket_t *sock = (isc_socket_t *)sevent->ev_sender; + isc_result_t result; + + REQUIRE(conn->sending); + + UNUSED(task); + + conn->sending = ISC_FALSE; + + if (sevent->result != ISC_R_SUCCESS && + sevent->result != ISC_R_CANCELED) + { + char socktext[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_t peeraddr; + + (void)isc_socket_getpeername(sock, &peeraddr); + isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext)); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, + "error sending command response to %s: %s", + socktext, isc_result_totext(sevent->result)); + } + isc_event_free(&event); + + result = isccc_ccmsg_readmessage(&conn->ccmsg, listener->task, + control_recvmessage, conn); + if (result != ISC_R_SUCCESS) { + isc_socket_detach(&conn->sock); + maybe_free_connection(conn); + maybe_free_listener(listener); + } +} + +static inline void +log_invalid(isccc_ccmsg_t *ccmsg, isc_result_t result) { + char socktext[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_t peeraddr; + + (void)isc_socket_getpeername(ccmsg->sock, &peeraddr); + isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext)); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_CONTROL, ISC_LOG_ERROR, + "invalid command from %s: %s", + socktext, isc_result_totext(result)); +} + +static void +control_recvmessage(isc_task_t *task, isc_event_t *event) { + controlconnection_t *conn; + controllistener_t *listener; + controlkey_t *key; + isccc_sexpr_t *request = NULL; + isccc_sexpr_t *response = NULL; + isccc_region_t ccregion; + isccc_region_t secret; + isc_stdtime_t now; + isc_buffer_t b; + isc_region_t r; + isc_uint32_t len; + isc_buffer_t text; + char textarray[1024]; + isc_result_t result; + isc_result_t eresult; + isccc_sexpr_t *_ctrl; + isccc_time_t sent; + isccc_time_t exp; + isc_uint32_t nonce; + + REQUIRE(event->ev_type == ISCCC_EVENT_CCMSG); + + conn = event->ev_arg; + listener = conn->listener; + secret.rstart = NULL; + + /* Is the server shutting down? */ + if (listener->controls->shuttingdown) + goto cleanup; + + if (conn->ccmsg.result != ISC_R_SUCCESS) { + if (conn->ccmsg.result != ISC_R_CANCELED && + conn->ccmsg.result != ISC_R_EOF) + log_invalid(&conn->ccmsg, conn->ccmsg.result); + goto cleanup; + } + + request = NULL; + + for (key = ISC_LIST_HEAD(listener->keys); + key != NULL; + key = ISC_LIST_NEXT(key, link)) + { + ccregion.rstart = isc_buffer_base(&conn->ccmsg.buffer); + ccregion.rend = isc_buffer_used(&conn->ccmsg.buffer); + secret.rstart = isc_mem_get(listener->mctx, key->secret.length); + if (secret.rstart == NULL) + goto cleanup; + memcpy(secret.rstart, key->secret.base, key->secret.length); + secret.rend = secret.rstart + key->secret.length; + result = isccc_cc_fromwire(&ccregion, &request, &secret); + if (result == ISC_R_SUCCESS) + break; + isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret)); + if (result == ISCCC_R_BADAUTH) { + /* + * For some reason, request is non-NULL when + * isccc_cc_fromwire returns ISCCC_R_BADAUTH. + */ + if (request != NULL) + isccc_sexpr_free(&request); + } else { + log_invalid(&conn->ccmsg, result); + goto cleanup; + } + } + + if (key == NULL) { + log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH); + goto cleanup; + } + + /* We shouldn't be getting a reply. */ + if (isccc_cc_isreply(request)) { + log_invalid(&conn->ccmsg, ISC_R_FAILURE); + goto cleanup_request; + } + + isc_stdtime_get(&now); + + /* + * Limit exposure to replay attacks. + */ + _ctrl = isccc_alist_lookup(request, "_ctrl"); + if (_ctrl == NULL) { + log_invalid(&conn->ccmsg, ISC_R_FAILURE); + goto cleanup_request; + } + + if (isccc_cc_lookupuint32(_ctrl, "_tim", &sent) == ISC_R_SUCCESS) { + if ((sent + CLOCKSKEW) < now || (sent - CLOCKSKEW) > now) { + log_invalid(&conn->ccmsg, ISCCC_R_CLOCKSKEW); + goto cleanup_request; + } + } else { + log_invalid(&conn->ccmsg, ISC_R_FAILURE); + goto cleanup_request; + } + + /* + * Expire messages that are too old. + */ + if (isccc_cc_lookupuint32(_ctrl, "_exp", &exp) == ISC_R_SUCCESS && + now > exp) { + log_invalid(&conn->ccmsg, ISCCC_R_EXPIRED); + goto cleanup_request; + } + + /* + * Duplicate suppression (required for UDP). + */ + isccc_cc_cleansymtab(listener->controls->symtab, now); + result = isccc_cc_checkdup(listener->controls->symtab, request, now); + if (result != ISC_R_SUCCESS) { + if (result == ISC_R_EXISTS) + result = ISCCC_R_DUPLICATE; + log_invalid(&conn->ccmsg, result); + goto cleanup_request; + } + + if (conn->nonce != 0 && + (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS || + conn->nonce != nonce)) { + log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH); + goto cleanup_request; + } + + /* + * Establish nonce. + */ + while (conn->nonce == 0) + isc_random_get(&conn->nonce); + + isc_buffer_init(&text, textarray, sizeof(textarray)); + eresult = ns_control_docommand(request, &text); + + result = isccc_cc_createresponse(request, now, now + 60, &response); + if (result != ISC_R_SUCCESS) + goto cleanup_request; + if (eresult != ISC_R_SUCCESS) { + isccc_sexpr_t *data; + + data = isccc_alist_lookup(response, "_data"); + if (data != NULL) { + const char *estr = isc_result_totext(eresult); + if (isccc_cc_definestring(data, "err", estr) == NULL) + goto cleanup_response; + } + } + + if (isc_buffer_usedlength(&text) > 0) { + isccc_sexpr_t *data; + + data = isccc_alist_lookup(response, "_data"); + if (data != NULL) { + char *str = (char *)isc_buffer_base(&text); + if (isccc_cc_definestring(data, "text", str) == NULL) + goto cleanup_response; + } + } + + _ctrl = isccc_alist_lookup(response, "_ctrl"); + if (_ctrl == NULL || + isccc_cc_defineuint32(_ctrl, "_nonce", conn->nonce) == NULL) + goto cleanup_response; + + ccregion.rstart = conn->buffer + 4; + ccregion.rend = conn->buffer + sizeof(conn->buffer); + result = isccc_cc_towire(response, &ccregion, &secret); + if (result != ISC_R_SUCCESS) + goto cleanup_response; + isc_buffer_init(&b, conn->buffer, 4); + len = sizeof(conn->buffer) - REGION_SIZE(ccregion); + isc_buffer_putuint32(&b, len - 4); + r.base = conn->buffer; + r.length = len; + + result = isc_socket_send(conn->sock, &r, task, control_senddone, conn); + if (result != ISC_R_SUCCESS) + goto cleanup_response; + conn->sending = ISC_TRUE; + + isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret)); + isccc_sexpr_free(&request); + isccc_sexpr_free(&response); + return; + + cleanup_response: + isccc_sexpr_free(&response); + + cleanup_request: + isccc_sexpr_free(&request); + isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret)); + + cleanup: + isc_socket_detach(&conn->sock); + isccc_ccmsg_invalidate(&conn->ccmsg); + conn->ccmsg_valid = ISC_FALSE; + maybe_free_connection(conn); + maybe_free_listener(listener); +} + +static void +control_timeout(isc_task_t *task, isc_event_t *event) { + controlconnection_t *conn = event->ev_arg; + + UNUSED(task); + + isc_timer_detach(&conn->timer); + maybe_free_connection(conn); + + isc_event_free(&event); +} + +static isc_result_t +newconnection(controllistener_t *listener, isc_socket_t *sock) { + controlconnection_t *conn; + isc_interval_t interval; + isc_result_t result; + + conn = isc_mem_get(listener->mctx, sizeof(*conn)); + if (conn == NULL) + return (ISC_R_NOMEMORY); + + conn->sock = sock; + isccc_ccmsg_init(listener->mctx, sock, &conn->ccmsg); + conn->ccmsg_valid = ISC_TRUE; + conn->sending = ISC_FALSE; + conn->timer = NULL; + isc_interval_set(&interval, 60, 0); + result = isc_timer_create(ns_g_timermgr, isc_timertype_once, + NULL, &interval, listener->task, + control_timeout, conn, &conn->timer); + if (result != ISC_R_SUCCESS) + goto cleanup; + + conn->listener = listener; + conn->nonce = 0; + ISC_LINK_INIT(conn, link); + + result = isccc_ccmsg_readmessage(&conn->ccmsg, listener->task, + control_recvmessage, conn); + if (result != ISC_R_SUCCESS) + goto cleanup; + isccc_ccmsg_setmaxsize(&conn->ccmsg, 2048); + + ISC_LIST_APPEND(listener->connections, conn, link); + return (ISC_R_SUCCESS); + + cleanup: + isccc_ccmsg_invalidate(&conn->ccmsg); + if (conn->timer != NULL) + isc_timer_detach(&conn->timer); + isc_mem_put(listener->mctx, conn, sizeof(*conn)); + return (result); +} + +static void +control_newconn(isc_task_t *task, isc_event_t *event) { + isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event; + controllistener_t *listener = event->ev_arg; + isc_socket_t *sock; + isc_sockaddr_t peeraddr; + isc_result_t result; + + UNUSED(task); + + listener->listening = ISC_FALSE; + + if (nevent->result != ISC_R_SUCCESS) { + if (nevent->result == ISC_R_CANCELED) { + shutdown_listener(listener); + goto cleanup; + } + goto restart; + } + + sock = nevent->newsocket; + isc_socket_setname(sock, "control", NULL); + (void)isc_socket_getpeername(sock, &peeraddr); + if (listener->type == isc_sockettype_tcp && + !address_ok(&peeraddr, listener->acl)) { + char socktext[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext)); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, + "rejected command channel message from %s", + socktext); + isc_socket_detach(&sock); + goto restart; + } + + result = newconnection(listener, sock); + if (result != ISC_R_SUCCESS) { + char socktext[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext)); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, + "dropped command channel from %s: %s", + socktext, isc_result_totext(result)); + isc_socket_detach(&sock); + goto restart; + } + + restart: + control_next(listener); + cleanup: + isc_event_free(&event); +} + +static void +controls_shutdown(ns_controls_t *controls) { + controllistener_t *listener; + controllistener_t *next; + + for (listener = ISC_LIST_HEAD(controls->listeners); + listener != NULL; + listener = next) + { + /* + * This is asynchronous. As listeners shut down, they will + * call their callbacks. + */ + next = ISC_LIST_NEXT(listener, link); + shutdown_listener(listener); + } +} + +void +ns_controls_shutdown(ns_controls_t *controls) { + controls_shutdown(controls); + controls->shuttingdown = ISC_TRUE; +} + +static isc_result_t +cfgkeylist_find(const cfg_obj_t *keylist, const char *keyname, + const cfg_obj_t **objp) +{ + const cfg_listelt_t *element; + const char *str; + const cfg_obj_t *obj; + + for (element = cfg_list_first(keylist); + element != NULL; + element = cfg_list_next(element)) + { + obj = cfg_listelt_value(element); + str = cfg_obj_asstring(cfg_map_getname(obj)); + if (strcasecmp(str, keyname) == 0) + break; + } + if (element == NULL) + return (ISC_R_NOTFOUND); + obj = cfg_listelt_value(element); + *objp = obj; + return (ISC_R_SUCCESS); +} + +static isc_result_t +controlkeylist_fromcfg(const cfg_obj_t *keylist, isc_mem_t *mctx, + controlkeylist_t *keyids) +{ + const cfg_listelt_t *element; + char *newstr = NULL; + const char *str; + const cfg_obj_t *obj; + controlkey_t *key; + + for (element = cfg_list_first(keylist); + element != NULL; + element = cfg_list_next(element)) + { + obj = cfg_listelt_value(element); + str = cfg_obj_asstring(obj); + newstr = isc_mem_strdup(mctx, str); + if (newstr == NULL) + goto cleanup; + key = isc_mem_get(mctx, sizeof(*key)); + if (key == NULL) + goto cleanup; + key->keyname = newstr; + key->secret.base = NULL; + key->secret.length = 0; + ISC_LINK_INIT(key, link); + ISC_LIST_APPEND(*keyids, key, link); + newstr = NULL; + } + return (ISC_R_SUCCESS); + + cleanup: + if (newstr != NULL) + isc_mem_free(mctx, newstr); + free_controlkeylist(keyids, mctx); + return (ISC_R_NOMEMORY); +} + +static void +register_keys(const cfg_obj_t *control, const cfg_obj_t *keylist, + controlkeylist_t *keyids, isc_mem_t *mctx, const char *socktext) +{ + controlkey_t *keyid, *next; + const cfg_obj_t *keydef; + char secret[1024]; + isc_buffer_t b; + isc_result_t result; + + /* + * Find the keys corresponding to the keyids used by this listener. + */ + for (keyid = ISC_LIST_HEAD(*keyids); keyid != NULL; keyid = next) { + next = ISC_LIST_NEXT(keyid, link); + + result = cfgkeylist_find(keylist, keyid->keyname, &keydef); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, + "couldn't find key '%s' for use with " + "command channel %s", + keyid->keyname, socktext); + ISC_LIST_UNLINK(*keyids, keyid, link); + free_controlkey(keyid, mctx); + } else { + const cfg_obj_t *algobj = NULL; + const cfg_obj_t *secretobj = NULL; + const char *algstr = NULL; + const char *secretstr = NULL; + + (void)cfg_map_get(keydef, "algorithm", &algobj); + (void)cfg_map_get(keydef, "secret", &secretobj); + INSIST(algobj != NULL && secretobj != NULL); + + algstr = cfg_obj_asstring(algobj); + secretstr = cfg_obj_asstring(secretobj); + + if (ns_config_getkeyalgorithm(algstr, NULL, NULL) != + ISC_R_SUCCESS) + { + cfg_obj_log(control, ns_g_lctx, + ISC_LOG_WARNING, + "unsupported algorithm '%s' in " + "key '%s' for use with command " + "channel %s", + algstr, keyid->keyname, socktext); + ISC_LIST_UNLINK(*keyids, keyid, link); + free_controlkey(keyid, mctx); + continue; + } + + isc_buffer_init(&b, secret, sizeof(secret)); + result = isc_base64_decodestring(secretstr, &b); + + if (result != ISC_R_SUCCESS) { + cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING, + "secret for key '%s' on " + "command channel %s: %s", + keyid->keyname, socktext, + isc_result_totext(result)); + ISC_LIST_UNLINK(*keyids, keyid, link); + free_controlkey(keyid, mctx); + continue; + } + + keyid->secret.length = isc_buffer_usedlength(&b); + keyid->secret.base = isc_mem_get(mctx, + keyid->secret.length); + if (keyid->secret.base == NULL) { + cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING, + "couldn't register key '%s': " + "out of memory", keyid->keyname); + ISC_LIST_UNLINK(*keyids, keyid, link); + free_controlkey(keyid, mctx); + break; + } + memcpy(keyid->secret.base, isc_buffer_base(&b), + keyid->secret.length); + } + } +} + +#define CHECK(x) \ + do { \ + result = (x); \ + if (result != ISC_R_SUCCESS) \ + goto cleanup; \ + } while (0) + +static isc_result_t +get_rndckey(isc_mem_t *mctx, controlkeylist_t *keyids) { + isc_result_t result; + cfg_parser_t *pctx = NULL; + cfg_obj_t *config = NULL; + const cfg_obj_t *key = NULL; + const cfg_obj_t *algobj = NULL; + const cfg_obj_t *secretobj = NULL; + const char *algstr = NULL; + const char *secretstr = NULL; + controlkey_t *keyid = NULL; + char secret[1024]; + isc_buffer_t b; + + CHECK(cfg_parser_create(mctx, ns_g_lctx, &pctx)); + CHECK(cfg_parse_file(pctx, ns_g_keyfile, &cfg_type_rndckey, &config)); + CHECK(cfg_map_get(config, "key", &key)); + + keyid = isc_mem_get(mctx, sizeof(*keyid)); + if (keyid == NULL) + CHECK(ISC_R_NOMEMORY); + keyid->keyname = isc_mem_strdup(mctx, + cfg_obj_asstring(cfg_map_getname(key))); + keyid->secret.base = NULL; + keyid->secret.length = 0; + ISC_LINK_INIT(keyid, link); + if (keyid->keyname == NULL) + CHECK(ISC_R_NOMEMORY); + + CHECK(bind9_check_key(key, ns_g_lctx)); + + (void)cfg_map_get(key, "algorithm", &algobj); + (void)cfg_map_get(key, "secret", &secretobj); + INSIST(algobj != NULL && secretobj != NULL); + + algstr = cfg_obj_asstring(algobj); + secretstr = cfg_obj_asstring(secretobj); + + if (ns_config_getkeyalgorithm(algstr, NULL, NULL) != ISC_R_SUCCESS) { + cfg_obj_log(key, ns_g_lctx, + ISC_LOG_WARNING, + "unsupported algorithm '%s' in " + "key '%s' for use with command " + "channel", + algstr, keyid->keyname); + goto cleanup; + } + + isc_buffer_init(&b, secret, sizeof(secret)); + result = isc_base64_decodestring(secretstr, &b); + + if (result != ISC_R_SUCCESS) { + cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, + "secret for key '%s' on command channel: %s", + keyid->keyname, isc_result_totext(result)); + CHECK(result); + } + + keyid->secret.length = isc_buffer_usedlength(&b); + keyid->secret.base = isc_mem_get(mctx, + keyid->secret.length); + if (keyid->secret.base == NULL) { + cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, + "couldn't register key '%s': " + "out of memory", keyid->keyname); + CHECK(ISC_R_NOMEMORY); + } + memcpy(keyid->secret.base, isc_buffer_base(&b), + keyid->secret.length); + ISC_LIST_APPEND(*keyids, keyid, link); + keyid = NULL; + result = ISC_R_SUCCESS; + + cleanup: + if (keyid != NULL) + free_controlkey(keyid, mctx); + if (config != NULL) + cfg_obj_destroy(pctx, &config); + if (pctx != NULL) + cfg_parser_destroy(&pctx); + return (result); +} + +/* + * Ensures that both '*global_keylistp' and '*control_keylistp' are + * valid or both are NULL. + */ +static void +get_key_info(const cfg_obj_t *config, const cfg_obj_t *control, + const cfg_obj_t **global_keylistp, + const cfg_obj_t **control_keylistp) +{ + isc_result_t result; + const cfg_obj_t *control_keylist = NULL; + const cfg_obj_t *global_keylist = NULL; + + REQUIRE(global_keylistp != NULL && *global_keylistp == NULL); + REQUIRE(control_keylistp != NULL && *control_keylistp == NULL); + + control_keylist = cfg_tuple_get(control, "keys"); + + if (!cfg_obj_isvoid(control_keylist) && + cfg_list_first(control_keylist) != NULL) { + result = cfg_map_get(config, "key", &global_keylist); + + if (result == ISC_R_SUCCESS) { + *global_keylistp = global_keylist; + *control_keylistp = control_keylist; + } + } +} + +static void +update_listener(ns_controls_t *cp, controllistener_t **listenerp, + const cfg_obj_t *control, const cfg_obj_t *config, + isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, + const char *socktext, isc_sockettype_t type) +{ + controllistener_t *listener; + const cfg_obj_t *allow; + const cfg_obj_t *global_keylist = NULL; + const cfg_obj_t *control_keylist = NULL; + dns_acl_t *new_acl = NULL; + controlkeylist_t keys; + isc_result_t result = ISC_R_SUCCESS; + + for (listener = ISC_LIST_HEAD(cp->listeners); + listener != NULL; + listener = ISC_LIST_NEXT(listener, link)) + if (isc_sockaddr_equal(addr, &listener->address)) + break; + + if (listener == NULL) { + *listenerp = NULL; + return; + } + + /* + * There is already a listener for this sockaddr. + * Update the access list and key information. + * + * First try to deal with the key situation. There are a few + * possibilities: + * (a) It had an explicit keylist and still has an explicit keylist. + * (b) It had an automagic key and now has an explicit keylist. + * (c) It had an explicit keylist and now needs an automagic key. + * (d) It has an automagic key and still needs the automagic key. + * + * (c) and (d) are the annoying ones. The caller needs to know + * that it should use the automagic configuration for key information + * in place of the named.conf configuration. + * + * XXXDCL There is one other hazard that has not been dealt with, + * the problem that if a key change is being caused by a control + * channel reload, then the response will be with the new key + * and not able to be decrypted by the client. + */ + if (control != NULL) + get_key_info(config, control, &global_keylist, + &control_keylist); + + if (control_keylist != NULL) { + INSIST(global_keylist != NULL); + + ISC_LIST_INIT(keys); + result = controlkeylist_fromcfg(control_keylist, + listener->mctx, &keys); + if (result == ISC_R_SUCCESS) { + free_controlkeylist(&listener->keys, listener->mctx); + listener->keys = keys; + register_keys(control, global_keylist, &listener->keys, + listener->mctx, socktext); + } + } else { + free_controlkeylist(&listener->keys, listener->mctx); + result = get_rndckey(listener->mctx, &listener->keys); + } + + if (result != ISC_R_SUCCESS && global_keylist != NULL) { + /* + * This message might be a little misleading since the + * "new keys" might in fact be identical to the old ones, + * but tracking whether they are identical just for the + * sake of avoiding this message would be too much trouble. + */ + if (control != NULL) + cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, + "couldn't install new keys for " + "command channel %s: %s", + socktext, isc_result_totext(result)); + else + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, + "couldn't install new keys for " + "command channel %s: %s", + socktext, isc_result_totext(result)); + } + + /* + * Now, keep the old access list unless a new one can be made. + */ + if (control != NULL && type == isc_sockettype_tcp) { + allow = cfg_tuple_get(control, "allow"); + result = cfg_acl_fromconfig(allow, config, ns_g_lctx, + aclconfctx, listener->mctx, 0, + &new_acl); + } else { + result = dns_acl_any(listener->mctx, &new_acl); + } + + if (result == ISC_R_SUCCESS) { + dns_acl_detach(&listener->acl); + dns_acl_attach(new_acl, &listener->acl); + dns_acl_detach(&new_acl); + /* XXXDCL say the old acl is still used? */ + } else if (control != NULL) + cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, + "couldn't install new acl for " + "command channel %s: %s", + socktext, isc_result_totext(result)); + else + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, + "couldn't install new acl for " + "command channel %s: %s", + socktext, isc_result_totext(result)); + + if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) { + isc_uint32_t perm, owner, group; + perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm")); + owner = cfg_obj_asuint32(cfg_tuple_get(control, "owner")); + group = cfg_obj_asuint32(cfg_tuple_get(control, "group")); + result = ISC_R_SUCCESS; + if (listener->perm != perm || listener->owner != owner || + listener->group != group) + result = isc_socket_permunix(&listener->address, perm, + owner, group); + if (result == ISC_R_SUCCESS) { + listener->perm = perm; + listener->owner = owner; + listener->group = group; + } else if (control != NULL) + cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, + "couldn't update ownership/permission for " + "command channel %s", socktext); + } + + *listenerp = listener; +} + +static void +add_listener(ns_controls_t *cp, controllistener_t **listenerp, + const cfg_obj_t *control, const cfg_obj_t *config, + isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, + const char *socktext, isc_sockettype_t type) +{ + isc_mem_t *mctx = cp->server->mctx; + controllistener_t *listener; + const cfg_obj_t *allow; + const cfg_obj_t *global_keylist = NULL; + const cfg_obj_t *control_keylist = NULL; + dns_acl_t *new_acl = NULL; + isc_result_t result = ISC_R_SUCCESS; + + listener = isc_mem_get(mctx, sizeof(*listener)); + if (listener == NULL) + result = ISC_R_NOMEMORY; + + if (result == ISC_R_SUCCESS) { + listener->controls = cp; + listener->mctx = mctx; + listener->task = cp->server->task; + listener->address = *addr; + listener->sock = NULL; + listener->listening = ISC_FALSE; + listener->exiting = ISC_FALSE; + listener->acl = NULL; + listener->type = type; + listener->perm = 0; + listener->owner = 0; + listener->group = 0; + ISC_LINK_INIT(listener, link); + ISC_LIST_INIT(listener->keys); + ISC_LIST_INIT(listener->connections); + + /* + * Make the acl. + */ + if (control != NULL && type == isc_sockettype_tcp) { + allow = cfg_tuple_get(control, "allow"); + result = cfg_acl_fromconfig(allow, config, ns_g_lctx, + aclconfctx, mctx, 0, + &new_acl); + } else { + result = dns_acl_any(mctx, &new_acl); + } + } + + if (result == ISC_R_SUCCESS) { + dns_acl_attach(new_acl, &listener->acl); + dns_acl_detach(&new_acl); + + if (config != NULL) + get_key_info(config, control, &global_keylist, + &control_keylist); + + if (control_keylist != NULL) { + result = controlkeylist_fromcfg(control_keylist, + listener->mctx, + &listener->keys); + if (result == ISC_R_SUCCESS) + register_keys(control, global_keylist, + &listener->keys, + listener->mctx, socktext); + } else + result = get_rndckey(mctx, &listener->keys); + + if (result != ISC_R_SUCCESS && control != NULL) + cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, + "couldn't install keys for " + "command channel %s: %s", + socktext, isc_result_totext(result)); + } + + if (result == ISC_R_SUCCESS) { + int pf = isc_sockaddr_pf(&listener->address); + if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) || +#ifdef ISC_PLATFORM_HAVESYSUNH + (pf == AF_UNIX && isc_net_probeunix() != ISC_R_SUCCESS) || +#endif + (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS)) + result = ISC_R_FAMILYNOSUPPORT; + } + + if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) + isc_socket_cleanunix(&listener->address, ISC_FALSE); + + if (result == ISC_R_SUCCESS) + result = isc_socket_create(ns_g_socketmgr, + isc_sockaddr_pf(&listener->address), + type, &listener->sock); + if (result == ISC_R_SUCCESS) + isc_socket_setname(listener->sock, "control", NULL); + + if (result == ISC_R_SUCCESS) + result = isc_socket_bind(listener->sock, &listener->address, + ISC_SOCKET_REUSEADDRESS); + + if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) { + listener->perm = cfg_obj_asuint32(cfg_tuple_get(control, + "perm")); + listener->owner = cfg_obj_asuint32(cfg_tuple_get(control, + "owner")); + listener->group = cfg_obj_asuint32(cfg_tuple_get(control, + "group")); + result = isc_socket_permunix(&listener->address, listener->perm, + listener->owner, listener->group); + } + if (result == ISC_R_SUCCESS) + result = control_listen(listener); + + if (result == ISC_R_SUCCESS) + result = control_accept(listener); + + if (result == ISC_R_SUCCESS) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE, + "command channel listening on %s", socktext); + *listenerp = listener; + + } else { + if (listener != NULL) { + listener->exiting = ISC_TRUE; + free_listener(listener); + } + + if (control != NULL) + cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, + "couldn't add command channel %s: %s", + socktext, isc_result_totext(result)); + else + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE, + "couldn't add command channel %s: %s", + socktext, isc_result_totext(result)); + + *listenerp = NULL; + } + + /* XXXDCL return error results? fail hard? */ +} + +isc_result_t +ns_controls_configure(ns_controls_t *cp, const cfg_obj_t *config, + cfg_aclconfctx_t *aclconfctx) +{ + controllistener_t *listener; + controllistenerlist_t new_listeners; + const cfg_obj_t *controlslist = NULL; + const cfg_listelt_t *element, *element2; + char socktext[ISC_SOCKADDR_FORMATSIZE]; + + ISC_LIST_INIT(new_listeners); + + /* + * Get the list of named.conf 'controls' statements. + */ + (void)cfg_map_get(config, "controls", &controlslist); + + /* + * Run through the new control channel list, noting sockets that + * are already being listened on and moving them to the new list. + * + * Identifying duplicate addr/port combinations is left to either + * the underlying config code, or to the bind attempt getting an + * address-in-use error. + */ + if (controlslist != NULL) { + for (element = cfg_list_first(controlslist); + element != NULL; + element = cfg_list_next(element)) { + const cfg_obj_t *controls; + const cfg_obj_t *inetcontrols = NULL; + + controls = cfg_listelt_value(element); + (void)cfg_map_get(controls, "inet", &inetcontrols); + if (inetcontrols == NULL) + continue; + + for (element2 = cfg_list_first(inetcontrols); + element2 != NULL; + element2 = cfg_list_next(element2)) { + const cfg_obj_t *control; + const cfg_obj_t *obj; + isc_sockaddr_t addr; + + /* + * The parser handles BIND 8 configuration file + * syntax, so it allows unix phrases as well + * inet phrases with no keys{} clause. + */ + control = cfg_listelt_value(element2); + + obj = cfg_tuple_get(control, "address"); + addr = *cfg_obj_assockaddr(obj); + if (isc_sockaddr_getport(&addr) == 0) + isc_sockaddr_setport(&addr, + NS_CONTROL_PORT); + + isc_sockaddr_format(&addr, socktext, + sizeof(socktext)); + + isc_log_write(ns_g_lctx, + NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_CONTROL, + ISC_LOG_DEBUG(9), + "processing control channel %s", + socktext); + + update_listener(cp, &listener, control, config, + &addr, aclconfctx, socktext, + isc_sockettype_tcp); + + if (listener != NULL) + /* + * Remove the listener from the old + * list, so it won't be shut down. + */ + ISC_LIST_UNLINK(cp->listeners, + listener, link); + else + /* + * This is a new listener. + */ + add_listener(cp, &listener, control, + config, &addr, aclconfctx, + socktext, + isc_sockettype_tcp); + + if (listener != NULL) + ISC_LIST_APPEND(new_listeners, + listener, link); + } + } + for (element = cfg_list_first(controlslist); + element != NULL; + element = cfg_list_next(element)) { + const cfg_obj_t *controls; + const cfg_obj_t *unixcontrols = NULL; + + controls = cfg_listelt_value(element); + (void)cfg_map_get(controls, "unix", &unixcontrols); + if (unixcontrols == NULL) + continue; + + for (element2 = cfg_list_first(unixcontrols); + element2 != NULL; + element2 = cfg_list_next(element2)) { + const cfg_obj_t *control; + const cfg_obj_t *path; + isc_sockaddr_t addr; + isc_result_t result; + + /* + * The parser handles BIND 8 configuration file + * syntax, so it allows unix phrases as well + * inet phrases with no keys{} clause. + */ + control = cfg_listelt_value(element2); + + path = cfg_tuple_get(control, "path"); + result = isc_sockaddr_frompath(&addr, + cfg_obj_asstring(path)); + if (result != ISC_R_SUCCESS) { + isc_log_write(ns_g_lctx, + NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_CONTROL, + ISC_LOG_DEBUG(9), + "control channel '%s': %s", + cfg_obj_asstring(path), + isc_result_totext(result)); + continue; + } + + isc_log_write(ns_g_lctx, + NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_CONTROL, + ISC_LOG_DEBUG(9), + "processing control channel '%s'", + cfg_obj_asstring(path)); + + update_listener(cp, &listener, control, config, + &addr, aclconfctx, + cfg_obj_asstring(path), + isc_sockettype_unix); + + if (listener != NULL) + /* + * Remove the listener from the old + * list, so it won't be shut down. + */ + ISC_LIST_UNLINK(cp->listeners, + listener, link); + else + /* + * This is a new listener. + */ + add_listener(cp, &listener, control, + config, &addr, aclconfctx, + cfg_obj_asstring(path), + isc_sockettype_unix); + + if (listener != NULL) + ISC_LIST_APPEND(new_listeners, + listener, link); + } + } + } else { + int i; + + for (i = 0; i < 2; i++) { + isc_sockaddr_t addr; + + if (i == 0) { + struct in_addr localhost; + + if (isc_net_probeipv4() != ISC_R_SUCCESS) + continue; + localhost.s_addr = htonl(INADDR_LOOPBACK); + isc_sockaddr_fromin(&addr, &localhost, 0); + } else { + if (isc_net_probeipv6() != ISC_R_SUCCESS) + continue; + isc_sockaddr_fromin6(&addr, + &in6addr_loopback, 0); + } + isc_sockaddr_setport(&addr, NS_CONTROL_PORT); + + isc_sockaddr_format(&addr, socktext, sizeof(socktext)); + + update_listener(cp, &listener, NULL, NULL, + &addr, NULL, socktext, + isc_sockettype_tcp); + + if (listener != NULL) + /* + * Remove the listener from the old + * list, so it won't be shut down. + */ + ISC_LIST_UNLINK(cp->listeners, + listener, link); + else + /* + * This is a new listener. + */ + add_listener(cp, &listener, NULL, NULL, + &addr, NULL, socktext, + isc_sockettype_tcp); + + if (listener != NULL) + ISC_LIST_APPEND(new_listeners, + listener, link); + } + } + + /* + * ns_control_shutdown() will stop whatever is on the global + * listeners list, which currently only has whatever sockaddrs + * were in the previous configuration (if any) that do not + * remain in the current configuration. + */ + controls_shutdown(cp); + + /* + * Put all of the valid listeners on the listeners list. + * Anything already on listeners in the process of shutting + * down will be taken care of by listen_done(). + */ + ISC_LIST_APPENDLIST(cp->listeners, new_listeners, link); + return (ISC_R_SUCCESS); +} + +isc_result_t +ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp) { + isc_mem_t *mctx = server->mctx; + isc_result_t result; + ns_controls_t *controls = isc_mem_get(mctx, sizeof(*controls)); + + if (controls == NULL) + return (ISC_R_NOMEMORY); + controls->server = server; + ISC_LIST_INIT(controls->listeners); + controls->shuttingdown = ISC_FALSE; + controls->symtab = NULL; + result = isccc_cc_createsymtab(&controls->symtab); + if (result != ISC_R_SUCCESS) { + isc_mem_put(server->mctx, controls, sizeof(*controls)); + return (result); + } + *ctrlsp = controls; + return (ISC_R_SUCCESS); +} + +void +ns_controls_destroy(ns_controls_t **ctrlsp) { + ns_controls_t *controls = *ctrlsp; + + REQUIRE(ISC_LIST_EMPTY(controls->listeners)); + + isccc_symtab_destroy(&controls->symtab); + isc_mem_put(controls->server->mctx, controls, sizeof(*controls)); + *ctrlsp = NULL; +} diff --git a/contrib/bind-9.5.2/bin/named/convertxsl.pl b/contrib/bind-9.5.2/bin/named/convertxsl.pl new file mode 100755 index 0000000000..722668eb29 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/convertxsl.pl @@ -0,0 +1,57 @@ +#!/usr/bin/env perl +# +# Copyright (C) 2006-2008 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: convertxsl.pl,v 1.9.60.5 2008/07/17 23:50:58 jinmei Exp $ + +use strict; +use warnings; + +my $rev = '$Id: convertxsl.pl,v 1.9.60.5 2008/07/17 23:50:58 jinmei Exp $'; +$rev =~ s/\$//g; +$rev =~ s/,v//g; +$rev =~ s/Id: //; + +my $xsl = "unknown"; +my $lines = ''; + +while (<>) { + chomp; + # pickout the id for comment. + $xsl = $_ if (//); + # convert Id string to a form not recognisable by cvs. + $_ =~ s///; + s/[\ \t]+/ /g; + s/\>\ \\.*//; +$xsl =~ s/,v//; + +print "/*\n * Generated by $rev \n * From $xsl\n */\n"; +print 'static char xslmsg[] =',"\n"; +print $lines; + +print ';', "\n"; diff --git a/contrib/bind-9.5.2/bin/named/include/named/builtin.h b/contrib/bind-9.5.2/bin/named/include/named/builtin.h new file mode 100644 index 0000000000..a5185ba60f --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/builtin.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001 Internet Software Consortium. + * + * 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: builtin.h,v 1.6 2007/06/19 23:46:59 tbox Exp $ */ + +#ifndef NAMED_BUILTIN_H +#define NAMED_BUILTIN_H 1 + +/*! \file */ + +#include + +isc_result_t ns_builtin_init(void); + +void ns_builtin_deinit(void); + +#endif /* NAMED_BUILTIN_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/client.h b/contrib/bind-9.5.2/bin/named/include/named/client.h new file mode 100644 index 0000000000..8efea4ac28 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/client.h @@ -0,0 +1,368 @@ +/* + * Copyright (C) 2004-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 + * 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.82.128.4 2009/01/19 23:47:01 tbox Exp $ */ + +#ifndef NAMED_CLIENT_H +#define NAMED_CLIENT_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file + * \brief + * This module defines two objects, ns_client_t and ns_clientmgr_t. + * + * An ns_client_t object handles incoming DNS requests from clients + * on a given network interface. + * + * Each ns_client_t object can handle only one TCP connection or UDP + * request at a time. Therefore, several ns_client_t objects are + * typically created to serve each network interface, e.g., one + * for handling TCP requests and a few (one per CPU) for handling + * UDP requests. + * + * Incoming requests are classified as queries, zone transfer + * requests, update requests, notify requests, etc, and handed off + * to the appropriate request handler. When the request has been + * fully handled (which can be much later), the ns_client_t must be + * notified of this by calling one of the following functions + * exactly once in the context of its task: + * \code + * ns_client_send() (sending a non-error response) + * ns_client_sendraw() (sending a raw response) + * ns_client_error() (sending an error response) + * ns_client_next() (sending no response) + *\endcode + * This will release any resources used by the request and + * and allow the ns_client_t to listen for the next request. + * + * A ns_clientmgr_t manages a number of ns_client_t objects. + * New ns_client_t objects are created by calling + * ns_clientmgr_createclients(). They are destroyed by + * destroying their manager. + */ + +/*** + *** Imports + ***/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +/*** + *** Types + ***/ + +typedef ISC_LIST(ns_client_t) client_list_t; + +/*% nameserver client structure */ +struct ns_client { + unsigned int magic; + isc_mem_t * mctx; + ns_clientmgr_t * manager; + int state; + int newstate; + int naccepts; + int nreads; + int nsends; + int nrecvs; + int nupdates; + int nctls; + int references; + unsigned int attributes; + isc_task_t * task; + dns_view_t * view; + dns_dispatch_t * dispatch; + isc_socket_t * udpsocket; + isc_socket_t * tcplistener; + isc_socket_t * tcpsocket; + unsigned char * tcpbuf; + dns_tcpmsg_t tcpmsg; + isc_boolean_t tcpmsg_valid; + isc_timer_t * timer; + isc_boolean_t timerset; + dns_message_t * message; + isc_socketevent_t * sendevent; + isc_socketevent_t * recvevent; + unsigned char * recvbuf; + dns_rdataset_t * opt; + isc_uint16_t udpsize; + isc_uint16_t extflags; + isc_int16_t ednsversion; /* -1 noedns */ + void (*next)(ns_client_t *); + void (*shutdown)(void *arg, isc_result_t result); + void *shutdown_arg; + ns_query_t query; + isc_stdtime_t requesttime; + isc_stdtime_t now; + dns_name_t signername; /*%< [T]SIG key name */ + dns_name_t * signer; /*%< NULL if not valid sig */ + isc_boolean_t mortal; /*%< Die after handling request */ + isc_quota_t *tcpquota; + isc_quota_t *recursionquota; + ns_interface_t *interface; + isc_sockaddr_t peeraddr; + isc_boolean_t peeraddr_valid; + struct in6_pktinfo pktinfo; + isc_event_t ctlevent; + /*% + * Information about recent FORMERR response(s), for + * FORMERR loop avoidance. This is separate for each + * client object rather than global only to avoid + * the need for locking. + */ + struct { + isc_sockaddr_t addr; + isc_stdtime_t time; + dns_messageid_t id; + } formerrcache; + ISC_LINK(ns_client_t) link; + /*% + * The list 'link' is part of, or NULL if not on any list. + */ + client_list_t *list; +}; + +#define NS_CLIENT_MAGIC ISC_MAGIC('N','S','C','c') +#define NS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, NS_CLIENT_MAGIC) + +#define NS_CLIENTATTR_TCP 0x01 +#define NS_CLIENTATTR_RA 0x02 /*%< Client gets recursive service */ +#define NS_CLIENTATTR_PKTINFO 0x04 /*%< pktinfo is valid */ +#define NS_CLIENTATTR_MULTICAST 0x08 /*%< recv'd from multicast */ +#define NS_CLIENTATTR_WANTDNSSEC 0x10 /*%< include dnssec records */ +#define NS_CLIENTATTR_WANTNSID 0x20 /*%< include nameserver ID */ + +extern unsigned int ns_client_requests; + +/*** + *** Functions + ***/ + +/*% + * Note! These ns_client_ routines MUST be called ONLY from the client's + * task in order to ensure synchronization. + */ + +void +ns_client_send(ns_client_t *client); +/*% + * Finish processing the current client request and + * send client->message as a response. + * \brief + * Note! These ns_client_ routines MUST be called ONLY from the client's + * task in order to ensure synchronization. + */ + +void +ns_client_sendraw(ns_client_t *client, dns_message_t *msg); +/*% + * Finish processing the current client request and + * send msg as a response using client->message->id for the id. + */ + +void +ns_client_error(ns_client_t *client, isc_result_t result); +/*% + * Finish processing the current client request and return + * an error response to the client. The error response + * will have an RCODE determined by 'result'. + */ + +void +ns_client_next(ns_client_t *client, isc_result_t result); +/*% + * Finish processing the current client request, + * return no response to the client. + */ + +isc_boolean_t +ns_client_shuttingdown(ns_client_t *client); +/*% + * Return ISC_TRUE iff the client is currently shutting down. + */ + +void +ns_client_attach(ns_client_t *source, ns_client_t **target); +/*% + * Attach '*targetp' to 'source'. + */ + +void +ns_client_detach(ns_client_t **clientp); +/*% + * Detach '*clientp' from its client. + */ + +isc_result_t +ns_client_replace(ns_client_t *client); +/*% + * Try to replace the current client with a new one, so that the + * current one can go off and do some lengthy work without + * leaving the dispatch/socket without service. + */ + +void +ns_client_settimeout(ns_client_t *client, unsigned int seconds); +/*% + * Set a timer in the client to go off in the specified amount of time. + */ + +isc_result_t +ns_clientmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, + isc_timermgr_t *timermgr, ns_clientmgr_t **managerp); +/*% + * Create a client manager. + */ + +void +ns_clientmgr_destroy(ns_clientmgr_t **managerp); +/*% + * Destroy a client manager and all ns_client_t objects + * managed by it. + */ + +isc_result_t +ns_clientmgr_createclients(ns_clientmgr_t *manager, unsigned int n, + ns_interface_t *ifp, isc_boolean_t tcp); +/*% + * Create up to 'n' clients listening on interface 'ifp'. + * If 'tcp' is ISC_TRUE, the clients will listen for TCP connections, + * otherwise for UDP requests. + */ + +isc_sockaddr_t * +ns_client_getsockaddr(ns_client_t *client); +/*% + * Get the socket address of the client whose request is + * currently being processed. + */ + +isc_result_t +ns_client_checkaclsilent(ns_client_t *client, + isc_sockaddr_t *sockaddr, + dns_acl_t *acl, + isc_boolean_t default_allow); + +/*% + * Convenience function for client request ACL checking. + * + * Check the current client request against 'acl'. If 'acl' + * is NULL, allow the request iff 'default_allow' is ISC_TRUE. + * If netaddr is NULL, check the ACL against client->peeraddr; + * otherwise check it against netaddr. + * + * Notes: + *\li This is appropriate for checking allow-update, + * allow-query, allow-transfer, etc. It is not appropriate + * for checking the blackhole list because we treat positive + * matches as "allow" and negative matches as "deny"; in + * the case of the blackhole list this would be backwards. + * + * Requires: + *\li 'client' points to a valid client. + *\li 'sockaddr' points to a valid address, or is NULL. + *\li 'acl' points to a valid ACL, or is NULL. + * + * Returns: + *\li ISC_R_SUCCESS if the request should be allowed + * \li ISC_R_REFUSED if the request should be denied + *\li No other return values are possible. + */ + +isc_result_t +ns_client_checkacl(ns_client_t *client, + isc_sockaddr_t *sockaddr, + const char *opname, dns_acl_t *acl, + isc_boolean_t default_allow, + int log_level); +/*% + * Like ns_client_checkaclsilent, except the outcome of the check is + * logged at log level 'log_level' if denied, and at debug 3 if approved. + * Log messages will refer to the request as an 'opname' request. + * + * Requires: + *\li 'client' points to a valid client. + *\li 'sockaddr' points to a valid address, or is NULL. + *\li 'acl' points to a valid ACL, or is NULL. + *\li 'opname' points to a null-terminated string. + */ + +void +ns_client_log(ns_client_t *client, isc_logcategory_t *category, + isc_logmodule_t *module, int level, + const char *fmt, ...) ISC_FORMAT_PRINTF(5, 6); + +void +ns_client_logv(ns_client_t *client, isc_logcategory_t *category, + isc_logmodule_t *module, int level, const char *fmt, va_list ap) ISC_FORMAT_PRINTF(5, 0); + +void +ns_client_aclmsg(const char *msg, dns_name_t *name, dns_rdatatype_t type, + dns_rdataclass_t rdclass, char *buf, size_t len); + +#define NS_CLIENT_ACLMSGSIZE(x) \ + (DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE + \ + DNS_RDATACLASS_FORMATSIZE + sizeof(x) + sizeof("'/'")) + +void +ns_client_recursing(ns_client_t *client); +/*% + * Add client to end of th recursing list. + */ + +void +ns_client_killoldestquery(ns_client_t *client); +/*% + * Kill the oldest recursive query (recursing list head). + */ + +void +ns_client_dumprecursing(FILE *f, ns_clientmgr_t *manager); +/*% + * Dump the outstanding recursive queries to 'f'. + */ + +void +ns_client_qnamereplace(ns_client_t *client, dns_name_t *name); +/*% + * Replace the qname. + */ + +isc_boolean_t +ns_client_isself(dns_view_t *myview, dns_tsigkey_t *mykey, + isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, + dns_rdataclass_t rdclass, void *arg); +/*% + * Isself callback. + */ + +#endif /* NAMED_CLIENT_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/config.h b/contrib/bind-9.5.2/bin/named/include/named/config.h new file mode 100644 index 0000000000..f7ceed81f7 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/config.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001, 2002 Internet Software Consortium. + * + * 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: config.h,v 1.14 2007/06/19 23:46:59 tbox Exp $ */ + +#ifndef NAMED_CONFIG_H +#define NAMED_CONFIG_H 1 + +/*! \file */ + +#include + +#include +#include + +isc_result_t +ns_config_parsedefaults(cfg_parser_t *parser, cfg_obj_t **conf); + +isc_result_t +ns_config_get(const cfg_obj_t **maps, const char* name, const cfg_obj_t **obj); + +isc_result_t +ns_checknames_get(const cfg_obj_t **maps, const char* name, + const cfg_obj_t **obj); + +int +ns_config_listcount(const cfg_obj_t *list); + +isc_result_t +ns_config_getclass(const cfg_obj_t *classobj, dns_rdataclass_t defclass, + dns_rdataclass_t *classp); + +isc_result_t +ns_config_gettype(const cfg_obj_t *typeobj, dns_rdatatype_t deftype, + dns_rdatatype_t *typep); + +dns_zonetype_t +ns_config_getzonetype(const cfg_obj_t *zonetypeobj); + +isc_result_t +ns_config_getiplist(const cfg_obj_t *config, const cfg_obj_t *list, + in_port_t defport, isc_mem_t *mctx, + isc_sockaddr_t **addrsp, isc_uint32_t *countp); + +void +ns_config_putiplist(isc_mem_t *mctx, isc_sockaddr_t **addrsp, + isc_uint32_t count); + +isc_result_t +ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list, + isc_mem_t *mctx, isc_sockaddr_t **addrsp, + dns_name_t ***keys, isc_uint32_t *countp); + +void +ns_config_putipandkeylist(isc_mem_t *mctx, isc_sockaddr_t **addrsp, + dns_name_t ***keys, isc_uint32_t count); + +isc_result_t +ns_config_getport(const cfg_obj_t *config, in_port_t *portp); + +isc_result_t +ns_config_getkeyalgorithm(const char *str, dns_name_t **name, + isc_uint16_t *digestbits); + +#endif /* NAMED_CONFIG_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/control.h b/contrib/bind-9.5.2/bin/named/include/named/control.h new file mode 100644 index 0000000000..d382ffe61d --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/control.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001-2003 Internet Software Consortium. + * + * 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: control.h,v 1.25 2007/06/19 23:46:59 tbox Exp $ */ + +#ifndef NAMED_CONTROL_H +#define NAMED_CONTROL_H 1 + +/*! \file + * \brief + * The name server command channel. + */ + +#include + +#include + +#include + +#define NS_CONTROL_PORT 953 + +#define NS_COMMAND_STOP "stop" +#define NS_COMMAND_HALT "halt" +#define NS_COMMAND_RELOAD "reload" +#define NS_COMMAND_RECONFIG "reconfig" +#define NS_COMMAND_REFRESH "refresh" +#define NS_COMMAND_RETRANSFER "retransfer" +#define NS_COMMAND_DUMPSTATS "stats" +#define NS_COMMAND_QUERYLOG "querylog" +#define NS_COMMAND_DUMPDB "dumpdb" +#define NS_COMMAND_TRACE "trace" +#define NS_COMMAND_NOTRACE "notrace" +#define NS_COMMAND_FLUSH "flush" +#define NS_COMMAND_FLUSHNAME "flushname" +#define NS_COMMAND_STATUS "status" +#define NS_COMMAND_TSIGLIST "tsig-list" +#define NS_COMMAND_TSIGDELETE "tsig-delete" +#define NS_COMMAND_FREEZE "freeze" +#define NS_COMMAND_UNFREEZE "unfreeze" +#define NS_COMMAND_THAW "thaw" +#define NS_COMMAND_TIMERPOKE "timerpoke" +#define NS_COMMAND_RECURSING "recursing" +#define NS_COMMAND_NULL "null" +#define NS_COMMAND_NOTIFY "notify" +#define NS_COMMAND_VALIDATION "validation" + +isc_result_t +ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp); +/*%< + * Create an initial, empty set of command channels for 'server'. + */ + +void +ns_controls_destroy(ns_controls_t **ctrlsp); +/*%< + * Destroy a set of command channels. + * + * Requires: + * Shutdown of the channels has completed. + */ + +isc_result_t +ns_controls_configure(ns_controls_t *controls, const cfg_obj_t *config, + cfg_aclconfctx_t *aclconfctx); +/*%< + * Configure zero or more command channels into 'controls' + * as defined in the configuration parse tree 'config'. + * The channels will evaluate ACLs in the context of + * 'aclconfctx'. + */ + +void +ns_controls_shutdown(ns_controls_t *controls); +/*%< + * Initiate shutdown of all the command channels in 'controls'. + */ + +isc_result_t +ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text); + +#endif /* NAMED_CONTROL_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/globals.h b/contrib/bind-9.5.2/bin/named/include/named/globals.h new file mode 100644 index 0000000000..90ebd001fb --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/globals.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2004-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 + * 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: globals.h,v 1.73.46.2 2008/10/24 01:44:15 tbox Exp $ */ + +#ifndef NAMED_GLOBALS_H +#define NAMED_GLOBALS_H 1 + +/*! \file */ + +#include +#include +#include + +#include + +#include + +#include + +#undef EXTERN +#undef INIT +#ifdef NS_MAIN +#define EXTERN +#define INIT(v) = (v) +#else +#define EXTERN extern +#define INIT(v) +#endif + +EXTERN isc_mem_t * ns_g_mctx INIT(NULL); +EXTERN unsigned int ns_g_cpus INIT(0); +EXTERN isc_taskmgr_t * ns_g_taskmgr INIT(NULL); +EXTERN dns_dispatchmgr_t * ns_g_dispatchmgr INIT(NULL); +EXTERN isc_entropy_t * ns_g_entropy INIT(NULL); +EXTERN isc_entropy_t * ns_g_fallbackentropy INIT(NULL); +EXTERN unsigned int ns_g_cpus_detected INIT(1); + +/* + * XXXRTH We're going to want multiple timer managers eventually. One + * for really short timers, another for client timers, and one + * for zone timers. + */ +EXTERN isc_timermgr_t * ns_g_timermgr INIT(NULL); +EXTERN isc_socketmgr_t * ns_g_socketmgr INIT(NULL); +EXTERN cfg_parser_t * ns_g_parser INIT(NULL); +EXTERN const char * ns_g_version INIT(VERSION); +EXTERN in_port_t ns_g_port INIT(0); +EXTERN in_port_t lwresd_g_listenport INIT(0); + +EXTERN ns_server_t * ns_g_server INIT(NULL); + +EXTERN isc_boolean_t ns_g_lwresdonly INIT(ISC_FALSE); + +/* + * Logging. + */ +EXTERN isc_log_t * ns_g_lctx INIT(NULL); +EXTERN isc_logcategory_t * ns_g_categories INIT(NULL); +EXTERN isc_logmodule_t * ns_g_modules INIT(NULL); +EXTERN unsigned int ns_g_debuglevel INIT(0); + +/* + * Current configuration information. + */ +EXTERN cfg_obj_t * ns_g_config INIT(NULL); +EXTERN const cfg_obj_t * ns_g_defaults INIT(NULL); +EXTERN const char * ns_g_conffile INIT(NS_SYSCONFDIR + "/named.conf"); +EXTERN const char * ns_g_keyfile INIT(NS_SYSCONFDIR + "/rndc.key"); +EXTERN const char * lwresd_g_conffile INIT(NS_SYSCONFDIR + "/lwresd.conf"); +EXTERN const char * lwresd_g_resolvconffile INIT("/etc" + "/resolv.conf"); +EXTERN isc_boolean_t ns_g_conffileset INIT(ISC_FALSE); +EXTERN isc_boolean_t lwresd_g_useresolvconf INIT(ISC_FALSE); +EXTERN isc_uint16_t ns_g_udpsize INIT(4096); + +/* + * Initial resource limits. + */ +EXTERN isc_resourcevalue_t ns_g_initstacksize INIT(0); +EXTERN isc_resourcevalue_t ns_g_initdatasize INIT(0); +EXTERN isc_resourcevalue_t ns_g_initcoresize INIT(0); +EXTERN isc_resourcevalue_t ns_g_initopenfiles INIT(0); + +/* + * Misc. + */ +EXTERN isc_boolean_t ns_g_coreok INIT(ISC_TRUE); +EXTERN const char * ns_g_chrootdir INIT(NULL); +EXTERN isc_boolean_t ns_g_foreground INIT(ISC_FALSE); +EXTERN isc_boolean_t ns_g_logstderr INIT(ISC_FALSE); + +EXTERN const char * ns_g_defaultpidfile INIT(NS_LOCALSTATEDIR + "/run/named.pid"); +EXTERN const char * lwresd_g_defaultpidfile INIT(NS_LOCALSTATEDIR + "/run/lwresd.pid"); +EXTERN const char * ns_g_username INIT(NULL); + +EXTERN int ns_g_listen INIT(3); +EXTERN isc_time_t ns_g_boottime; +EXTERN isc_boolean_t ns_g_memstatistics INIT(ISC_FALSE); + +#undef EXTERN +#undef INIT + +#endif /* NAMED_GLOBALS_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/interfacemgr.h b/contrib/bind-9.5.2/bin/named/include/named/interfacemgr.h new file mode 100644 index 0000000000..2724c393cd --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/interfacemgr.h @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2002 Internet Software Consortium. + * + * 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: interfacemgr.h,v 1.33 2007/06/19 23:46:59 tbox Exp $ */ + +#ifndef NAMED_INTERFACEMGR_H +#define NAMED_INTERFACEMGR_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file + * \brief + * The interface manager monitors the operating system's list + * of network interfaces, creating and destroying listeners + * as needed. + * + * Reliability: + *\li No impact expected. + * + * Resources: + * + * Security: + * \li The server will only be able to bind to the DNS port on + * newly discovered interfaces if it is running as root. + * + * Standards: + *\li The API for scanning varies greatly among operating systems. + * This module attempts to hide the differences. + */ + +/*** + *** Imports + ***/ + +#include +#include +#include + +#include + +#include +#include + +/*** + *** Types + ***/ + +#define IFACE_MAGIC ISC_MAGIC('I',':','-',')') +#define NS_INTERFACE_VALID(t) ISC_MAGIC_VALID(t, IFACE_MAGIC) + +#define NS_INTERFACEFLAG_ANYADDR 0x01U /*%< bound to "any" address */ + +/*% The nameserver interface structure */ +struct ns_interface { + unsigned int magic; /*%< Magic number. */ + ns_interfacemgr_t * mgr; /*%< Interface manager. */ + isc_mutex_t lock; + int references; /*%< Locked */ + unsigned int generation; /*%< Generation number. */ + isc_sockaddr_t addr; /*%< Address and port. */ + unsigned int flags; /*%< Interface characteristics */ + char name[32]; /*%< Null terminated. */ + dns_dispatch_t * udpdispatch; /*%< UDP dispatcher. */ + isc_socket_t * tcpsocket; /*%< TCP socket. */ + int ntcptarget; /*%< Desired number of concurrent + TCP accepts */ + int ntcpcurrent; /*%< Current ditto, locked */ + ns_clientmgr_t * clientmgr; /*%< Client manager. */ + ISC_LINK(ns_interface_t) link; +}; + +/*** + *** Functions + ***/ + +isc_result_t +ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, + isc_socketmgr_t *socketmgr, + dns_dispatchmgr_t *dispatchmgr, + ns_interfacemgr_t **mgrp); +/*% + * Create a new interface manager. + * + * Initially, the new manager will not listen on any interfaces. + * Call ns_interfacemgr_setlistenon() and/or ns_interfacemgr_setlistenon6() + * to set nonempty listen-on lists. + */ + +void +ns_interfacemgr_attach(ns_interfacemgr_t *source, ns_interfacemgr_t **target); + +void +ns_interfacemgr_detach(ns_interfacemgr_t **targetp); + +void +ns_interfacemgr_shutdown(ns_interfacemgr_t *mgr); + +void +ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose); +/*% + * Scan the operatings system's list of network interfaces + * and create listeners when new interfaces are discovered. + * Shut down the sockets for interfaces that go away. + * + * This should be called once on server startup and then + * periodically according to the 'interface-interval' option + * in named.conf. + */ + +void +ns_interfacemgr_adjust(ns_interfacemgr_t *mgr, ns_listenlist_t *list, + isc_boolean_t verbose); +/*% + * Similar to ns_interfacemgr_scan(), but this function also tries to see the + * need for an explicit listen-on when a list element in 'list' is going to + * override an already-listening a wildcard interface. + * + * This function does not update localhost and localnets ACLs. + * + * This should be called once on server startup, after configuring views and + * zones. + */ + +void +ns_interfacemgr_setlistenon4(ns_interfacemgr_t *mgr, ns_listenlist_t *value); +/*% + * Set the IPv4 "listen-on" list of 'mgr' to 'value'. + * The previous IPv4 listen-on list is freed. + */ + +void +ns_interfacemgr_setlistenon6(ns_interfacemgr_t *mgr, ns_listenlist_t *value); +/*% + * Set the IPv6 "listen-on" list of 'mgr' to 'value'. + * The previous IPv6 listen-on list is freed. + */ + +dns_aclenv_t * +ns_interfacemgr_getaclenv(ns_interfacemgr_t *mgr); + +void +ns_interface_attach(ns_interface_t *source, ns_interface_t **target); + +void +ns_interface_detach(ns_interface_t **targetp); + +void +ns_interface_shutdown(ns_interface_t *ifp); +/*% + * Stop listening for queries on interface 'ifp'. + * May safely be called multiple times. + */ + +void +ns_interfacemgr_dumprecursing(FILE *f, ns_interfacemgr_t *mgr); + +isc_boolean_t +ns_interfacemgr_listeningon(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr); + +#endif /* NAMED_INTERFACEMGR_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/listenlist.h b/contrib/bind-9.5.2/bin/named/include/named/listenlist.h new file mode 100644 index 0000000000..9e65d5df3a --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/listenlist.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * 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: listenlist.h,v 1.15 2007/06/19 23:46:59 tbox Exp $ */ + +#ifndef NAMED_LISTENLIST_H +#define NAMED_LISTENLIST_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file + * \brief + * "Listen lists", as in the "listen-on" configuration statement. + */ + +/*** + *** Imports + ***/ +#include + +#include + +/*** + *** Types + ***/ + +typedef struct ns_listenelt ns_listenelt_t; +typedef struct ns_listenlist ns_listenlist_t; + +struct ns_listenelt { + isc_mem_t * mctx; + in_port_t port; + dns_acl_t * acl; + ISC_LINK(ns_listenelt_t) link; +}; + +struct ns_listenlist { + isc_mem_t * mctx; + int refcount; + ISC_LIST(ns_listenelt_t) elts; +}; + +/*** + *** Functions + ***/ + +isc_result_t +ns_listenelt_create(isc_mem_t *mctx, in_port_t port, + dns_acl_t *acl, ns_listenelt_t **target); +/*% + * Create a listen-on list element. + */ + +void +ns_listenelt_destroy(ns_listenelt_t *elt); +/*% + * Destroy a listen-on list element. + */ + +isc_result_t +ns_listenlist_create(isc_mem_t *mctx, ns_listenlist_t **target); +/*% + * Create a new, empty listen-on list. + */ + +void +ns_listenlist_attach(ns_listenlist_t *source, ns_listenlist_t **target); +/*% + * Attach '*target' to '*source'. + */ + +void +ns_listenlist_detach(ns_listenlist_t **listp); +/*% + * Detach 'listp'. + */ + +isc_result_t +ns_listenlist_default(isc_mem_t *mctx, in_port_t port, + isc_boolean_t enabled, ns_listenlist_t **target); +/*% + * Create a listen-on list with default contents, matching + * all addresses with port 'port' (if 'enabled' is ISC_TRUE), + * or no addresses (if 'enabled' is ISC_FALSE). + */ + +#endif /* NAMED_LISTENLIST_H */ + + diff --git a/contrib/bind-9.5.2/bin/named/include/named/log.h b/contrib/bind-9.5.2/bin/named/include/named/log.h new file mode 100644 index 0000000000..d3a2e4fdba --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/log.h @@ -0,0 +1,99 @@ +/* + * 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 + * 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: log.h,v 1.25.128.2 2009/01/27 23:46:49 tbox Exp $ */ + +#ifndef NAMED_LOG_H +#define NAMED_LOG_H 1 + +/*! \file */ + +#include +#include + +#include + +#include /* Required for ns_g_(categories|modules). */ + +/* Unused slot 0. */ +#define NS_LOGCATEGORY_CLIENT (&ns_g_categories[1]) +#define NS_LOGCATEGORY_NETWORK (&ns_g_categories[2]) +#define NS_LOGCATEGORY_UPDATE (&ns_g_categories[3]) +#define NS_LOGCATEGORY_QUERIES (&ns_g_categories[4]) +#define NS_LOGCATEGORY_UNMATCHED (&ns_g_categories[5]) +#define NS_LOGCATEGORY_UPDATE_SECURITY (&ns_g_categories[6]) +#define NS_LOGCATEGORY_QUERY_EERRORS (&ns_g_categories[7]) + +/* + * Backwards compatibility. + */ +#define NS_LOGCATEGORY_GENERAL ISC_LOGCATEGORY_GENERAL + +#define NS_LOGMODULE_MAIN (&ns_g_modules[0]) +#define NS_LOGMODULE_CLIENT (&ns_g_modules[1]) +#define NS_LOGMODULE_SERVER (&ns_g_modules[2]) +#define NS_LOGMODULE_QUERY (&ns_g_modules[3]) +#define NS_LOGMODULE_INTERFACEMGR (&ns_g_modules[4]) +#define NS_LOGMODULE_UPDATE (&ns_g_modules[5]) +#define NS_LOGMODULE_XFER_IN (&ns_g_modules[6]) +#define NS_LOGMODULE_XFER_OUT (&ns_g_modules[7]) +#define NS_LOGMODULE_NOTIFY (&ns_g_modules[8]) +#define NS_LOGMODULE_CONTROL (&ns_g_modules[9]) +#define NS_LOGMODULE_LWRESD (&ns_g_modules[10]) + +isc_result_t +ns_log_init(isc_boolean_t safe); +/*% + * Initialize the logging system and set up an initial default + * logging default configuration that will be used until the + * config file has been read. + * + * If 'safe' is true, use a default configuration that refrains + * from opening files. This is to avoid creating log files + * as root. + */ + +isc_result_t +ns_log_setdefaultchannels(isc_logconfig_t *lcfg); +/*% + * Set up logging channels according to the named defaults, which + * may differ from the logging library defaults. Currently, + * this just means setting up default_debug. + */ + +isc_result_t +ns_log_setsafechannels(isc_logconfig_t *lcfg); +/*% + * Like ns_log_setdefaultchannels(), but omits any logging to files. + */ + +isc_result_t +ns_log_setdefaultcategory(isc_logconfig_t *lcfg); +/*% + * Set up "category default" to go to the right places. + */ + +isc_result_t +ns_log_setunmatchedcategory(isc_logconfig_t *lcfg); +/*% + * Set up "category unmatched" to go to the right places. + */ + +void +ns_log_shutdown(void); + +#endif /* NAMED_LOG_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/logconf.h b/contrib/bind-9.5.2/bin/named/include/named/logconf.h new file mode 100644 index 0000000000..03543452a9 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/logconf.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * 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: logconf.h,v 1.17 2007/06/19 23:46:59 tbox Exp $ */ + +#ifndef NAMED_LOGCONF_H +#define NAMED_LOGCONF_H 1 + +/*! \file */ + +#include + +isc_result_t +ns_log_configure(isc_logconfig_t *logconf, const cfg_obj_t *logstmt); +/*%< + * Set up the logging configuration in '*logconf' according to + * the named.conf data in 'logstmt'. + */ + +#endif /* NAMED_LOGCONF_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/lwaddr.h b/contrib/bind-9.5.2/bin/named/include/named/lwaddr.h new file mode 100644 index 0000000000..962aa91cd8 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/lwaddr.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * 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: lwaddr.h,v 1.8 2007/06/19 23:46:59 tbox Exp $ */ + +/*! \file */ + +#include +#include + +isc_result_t +lwaddr_netaddr_fromlwresaddr(isc_netaddr_t *na, lwres_addr_t *la); + +isc_result_t +lwaddr_sockaddr_fromlwresaddr(isc_sockaddr_t *sa, lwres_addr_t *la, + in_port_t port); + +isc_result_t +lwaddr_lwresaddr_fromnetaddr(lwres_addr_t *la, isc_netaddr_t *na); + +isc_result_t +lwaddr_lwresaddr_fromsockaddr(lwres_addr_t *la, isc_sockaddr_t *sa); diff --git a/contrib/bind-9.5.2/bin/named/include/named/lwdclient.h b/contrib/bind-9.5.2/bin/named/include/named/lwdclient.h new file mode 100644 index 0000000000..e0d31ab847 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/lwdclient.h @@ -0,0 +1,234 @@ +/* + * 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 + * 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: lwdclient.h,v 1.18.128.2 2009/01/19 23:47:01 tbox Exp $ */ + +#ifndef NAMED_LWDCLIENT_H +#define NAMED_LWDCLIENT_H 1 + +/*! \file */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#define LWRD_EVENTCLASS ISC_EVENTCLASS(4242) + +#define LWRD_SHUTDOWN (LWRD_EVENTCLASS + 0x0001) + +/*% Lightweight Resolver Daemon Client */ +struct ns_lwdclient { + isc_sockaddr_t address; /*%< where to reply */ + struct in6_pktinfo pktinfo; + isc_boolean_t pktinfo_valid; + ns_lwdclientmgr_t *clientmgr; /*%< our parent */ + ISC_LINK(ns_lwdclient_t) link; + unsigned int state; + void *arg; /*%< packet processing state */ + + /* + * Received data info. + */ + unsigned char buffer[LWRES_RECVLENGTH]; /*%< receive buffer */ + isc_uint32_t recvlength; /*%< length recv'd */ + lwres_lwpacket_t pkt; + + /*% + * Send data state. If sendbuf != buffer (that is, the send buffer + * isn't our receive buffer) it will be freed to the lwres_context_t. + */ + unsigned char *sendbuf; + isc_uint32_t sendlength; + isc_buffer_t recv_buffer; + + /*% + * gabn (get address by name) state info. + */ + dns_adbfind_t *find; + dns_adbfind_t *v4find; + dns_adbfind_t *v6find; + unsigned int find_wanted; /*%< Addresses we want */ + dns_fixedname_t query_name; + dns_fixedname_t target_name; + ns_lwsearchctx_t searchctx; + lwres_gabnresponse_t gabn; + + /*% + * gnba (get name by address) state info. + */ + lwres_gnbaresponse_t gnba; + dns_byaddr_t *byaddr; + unsigned int options; + isc_netaddr_t na; + + /*% + * grbn (get rrset by name) state info. + * + * Note: this also uses target_name and searchctx. + */ + lwres_grbnresponse_t grbn; + dns_lookup_t *lookup; + dns_rdatatype_t rdtype; + + /*% + * Alias and address info. This is copied up to the gabn/gnba + * structures eventually. + * + * XXXMLG We can keep all of this in a client since we only service + * three packet types right now. If we started handling more, + * we'd need to use "arg" above and allocate/destroy things. + */ + char *aliases[LWRES_MAX_ALIASES]; + isc_uint16_t aliaslen[LWRES_MAX_ALIASES]; + lwres_addr_t addrs[LWRES_MAX_ADDRS]; +}; + +/*% + * Client states. + * + * _IDLE The client is not doing anything at all. + * + * _RECV The client is waiting for data after issuing a socket recv(). + * + * _RECVDONE Data has been received, and is being processed. + * + * _FINDWAIT An adb (or other) request was made that cannot be satisfied + * immediately. An event will wake the client up. + * + * _SEND All data for a response has completed, and a reply was + * sent via a socket send() call. + * + * Badly formatted state table: + * + * IDLE -> RECV when client has a recv() queued. + * + * RECV -> RECVDONE when recvdone event received. + * + * RECVDONE -> SEND if the data for a reply is at hand. + * RECVDONE -> FINDWAIT if more searching is needed, and events will + * eventually wake us up again. + * + * FINDWAIT -> SEND when enough data was received to reply. + * + * SEND -> IDLE when a senddone event was received. + * + * At any time -> IDLE on error. Sometimes this will be -> SEND + * instead, if enough data is on hand to reply with a meaningful + * error. + * + * Packets which are badly formatted may or may not get error returns. + */ +#define NS_LWDCLIENT_STATEIDLE 1 +#define NS_LWDCLIENT_STATERECV 2 +#define NS_LWDCLIENT_STATERECVDONE 3 +#define NS_LWDCLIENT_STATEFINDWAIT 4 +#define NS_LWDCLIENT_STATESEND 5 +#define NS_LWDCLIENT_STATESENDDONE 6 + +#define NS_LWDCLIENT_ISIDLE(c) \ + ((c)->state == NS_LWDCLIENT_STATEIDLE) +#define NS_LWDCLIENT_ISRECV(c) \ + ((c)->state == NS_LWDCLIENT_STATERECV) +#define NS_LWDCLIENT_ISRECVDONE(c) \ + ((c)->state == NS_LWDCLIENT_STATERECVDONE) +#define NS_LWDCLIENT_ISFINDWAIT(c) \ + ((c)->state == NS_LWDCLIENT_STATEFINDWAIT) +#define NS_LWDCLIENT_ISSEND(c) \ + ((c)->state == NS_LWDCLIENT_STATESEND) + +/*% + * Overall magic test that means we're not idle. + */ +#define NS_LWDCLIENT_ISRUNNING(c) (!NS_LWDCLIENT_ISIDLE(c)) + +#define NS_LWDCLIENT_SETIDLE(c) \ + ((c)->state = NS_LWDCLIENT_STATEIDLE) +#define NS_LWDCLIENT_SETRECV(c) \ + ((c)->state = NS_LWDCLIENT_STATERECV) +#define NS_LWDCLIENT_SETRECVDONE(c) \ + ((c)->state = NS_LWDCLIENT_STATERECVDONE) +#define NS_LWDCLIENT_SETFINDWAIT(c) \ + ((c)->state = NS_LWDCLIENT_STATEFINDWAIT) +#define NS_LWDCLIENT_SETSEND(c) \ + ((c)->state = NS_LWDCLIENT_STATESEND) +#define NS_LWDCLIENT_SETSENDDONE(c) \ + ((c)->state = NS_LWDCLIENT_STATESENDDONE) + +/*% lightweight daemon client manager */ +struct ns_lwdclientmgr { + ns_lwreslistener_t *listener; + isc_mem_t *mctx; + isc_socket_t *sock; /*%< socket to use */ + dns_view_t *view; + lwres_context_t *lwctx; /*%< lightweight proto context */ + isc_task_t *task; /*%< owning task */ + unsigned int flags; + ISC_LINK(ns_lwdclientmgr_t) link; + ISC_LIST(ns_lwdclient_t) idle; /*%< idle client slots */ + ISC_LIST(ns_lwdclient_t) running; /*%< running clients */ +}; + +#define NS_LWDCLIENTMGR_FLAGRECVPENDING 0x00000001 +#define NS_LWDCLIENTMGR_FLAGSHUTTINGDOWN 0x00000002 + +isc_result_t +ns_lwdclientmgr_create(ns_lwreslistener_t *, unsigned int, isc_taskmgr_t *); + +void +ns_lwdclient_initialize(ns_lwdclient_t *, ns_lwdclientmgr_t *); + +isc_result_t +ns_lwdclient_startrecv(ns_lwdclientmgr_t *); + +void +ns_lwdclient_stateidle(ns_lwdclient_t *); + +void +ns_lwdclient_recv(isc_task_t *, isc_event_t *); + +void +ns_lwdclient_shutdown(isc_task_t *, isc_event_t *); + +void +ns_lwdclient_send(isc_task_t *, isc_event_t *); + +isc_result_t +ns_lwdclient_sendreply(ns_lwdclient_t *client, isc_region_t *r); + +/* + * Processing functions of various types. + */ +void ns_lwdclient_processgabn(ns_lwdclient_t *, lwres_buffer_t *); +void ns_lwdclient_processgnba(ns_lwdclient_t *, lwres_buffer_t *); +void ns_lwdclient_processgrbn(ns_lwdclient_t *, lwres_buffer_t *); +void ns_lwdclient_processnoop(ns_lwdclient_t *, lwres_buffer_t *); + +void ns_lwdclient_errorpktsend(ns_lwdclient_t *, isc_uint32_t); + +void ns_lwdclient_log(int level, const char *format, ...) + ISC_FORMAT_PRINTF(2, 3); + +#endif /* NAMED_LWDCLIENT_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/lwresd.h b/contrib/bind-9.5.2/bin/named/include/named/lwresd.h new file mode 100644 index 0000000000..565e58d7ab --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/lwresd.h @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * 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: lwresd.h,v 1.19 2007/06/19 23:46:59 tbox Exp $ */ + +#ifndef NAMED_LWRESD_H +#define NAMED_LWRESD_H 1 + +/*! \file */ + +#include +#include + +#include + +#include + +struct ns_lwresd { + unsigned int magic; + + isc_mutex_t lock; + dns_view_t *view; + ns_lwsearchlist_t *search; + unsigned int ndots; + isc_mem_t *mctx; + isc_boolean_t shutting_down; + unsigned int refs; +}; + +struct ns_lwreslistener { + unsigned int magic; + + isc_mutex_t lock; + isc_mem_t *mctx; + isc_sockaddr_t address; + ns_lwresd_t *manager; + isc_socket_t *sock; + unsigned int refs; + ISC_LIST(ns_lwdclientmgr_t) cmgrs; + ISC_LINK(ns_lwreslistener_t) link; +}; + +/*% + * Configure lwresd. + */ +isc_result_t +ns_lwresd_configure(isc_mem_t *mctx, const cfg_obj_t *config); + +isc_result_t +ns_lwresd_parseeresolvconf(isc_mem_t *mctx, cfg_parser_t *pctx, + cfg_obj_t **configp); + +/*% + * Trigger shutdown. + */ +void +ns_lwresd_shutdown(void); + +/* + * Manager functions + */ +/*% create manager */ +isc_result_t +ns_lwdmanager_create(isc_mem_t *mctx, const cfg_obj_t *lwres, + ns_lwresd_t **lwresdp); + +/*% attach to manager */ +void +ns_lwdmanager_attach(ns_lwresd_t *source, ns_lwresd_t **targetp); + +/*% detach from manager */ +void +ns_lwdmanager_detach(ns_lwresd_t **lwresdp); + +/* + * Listener functions + */ +/*% attach to listener */ +void +ns_lwreslistener_attach(ns_lwreslistener_t *source, + ns_lwreslistener_t **targetp); + +/*% detach from lister */ +void +ns_lwreslistener_detach(ns_lwreslistener_t **listenerp); + +/*% link client manager */ +void +ns_lwreslistener_unlinkcm(ns_lwreslistener_t *listener, ns_lwdclientmgr_t *cm); + +/*% unlink client manager */ +void +ns_lwreslistener_linkcm(ns_lwreslistener_t *listener, ns_lwdclientmgr_t *cm); + + + + +/* + * INTERNAL FUNCTIONS. + */ +void * +ns__lwresd_memalloc(void *arg, size_t size); + +void +ns__lwresd_memfree(void *arg, void *mem, size_t size); + +#endif /* NAMED_LWRESD_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/lwsearch.h b/contrib/bind-9.5.2/bin/named/include/named/lwsearch.h new file mode 100644 index 0000000000..c1b4f48f62 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/lwsearch.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * 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: lwsearch.h,v 1.9 2007/06/19 23:46:59 tbox Exp $ */ + +#ifndef NAMED_LWSEARCH_H +#define NAMED_LWSEARCH_H 1 + +#include +#include +#include + +#include + +#include + +/*! \file + * \brief + * Lightweight resolver search list types and routines. + * + * An ns_lwsearchlist_t holds a list of search path elements. + * + * An ns_lwsearchctx stores the state of search list during a lookup + * operation. + */ + +/*% An ns_lwsearchlist_t holds a list of search path elements. */ +struct ns_lwsearchlist { + unsigned int magic; + + isc_mutex_t lock; + isc_mem_t *mctx; + unsigned int refs; + dns_namelist_t names; +}; +/*% An ns_lwsearchctx stores the state of search list during a lookup operation. */ +struct ns_lwsearchctx { + dns_name_t *relname; + dns_name_t *searchname; + unsigned int ndots; + ns_lwsearchlist_t *list; + isc_boolean_t doneexact; + isc_boolean_t exactfirst; +}; + +isc_result_t +ns_lwsearchlist_create(isc_mem_t *mctx, ns_lwsearchlist_t **listp); +/*%< + * Create an empty search list object. + */ + +void +ns_lwsearchlist_attach(ns_lwsearchlist_t *source, ns_lwsearchlist_t **target); +/*%< + * Attach to a search list object. + */ + +void +ns_lwsearchlist_detach(ns_lwsearchlist_t **listp); +/*%< + * Detach from a search list object. + */ + +isc_result_t +ns_lwsearchlist_append(ns_lwsearchlist_t *list, dns_name_t *name); +/*%< + * Append an element to a search list. This creates a copy of the name. + */ + +void +ns_lwsearchctx_init(ns_lwsearchctx_t *sctx, ns_lwsearchlist_t *list, + dns_name_t *name, unsigned int ndots); +/*%< + * Creates a search list context structure. + */ + +void +ns_lwsearchctx_first(ns_lwsearchctx_t *sctx); +/*%< + * Moves the search list context iterator to the first element, which + * is usually the exact name. + */ + +isc_result_t +ns_lwsearchctx_next(ns_lwsearchctx_t *sctx); +/*%< + * Moves the search list context iterator to the next element. + */ + +isc_result_t +ns_lwsearchctx_current(ns_lwsearchctx_t *sctx, dns_name_t *absname); +/*%< + * Obtains the current name to be looked up. This involves either + * concatenating the name with a search path element, making an + * exact name absolute, or doing nothing. + */ + +#endif /* NAMED_LWSEARCH_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/main.h b/contrib/bind-9.5.2/bin/named/include/named/main.h new file mode 100644 index 0000000000..e834539467 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/main.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2002 Internet Software Consortium. + * + * 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: main.h,v 1.15 2007/06/19 23:46:59 tbox Exp $ */ + +#ifndef NAMED_MAIN_H +#define NAMED_MAIN_H 1 + +/*! \file */ + +void +ns_main_earlyfatal(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +void +ns_main_earlywarning(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +void +ns_main_setmemstats(const char *); + +#endif /* NAMED_MAIN_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/notify.h b/contrib/bind-9.5.2/bin/named/include/named/notify.h new file mode 100644 index 0000000000..a000cf96ce --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/notify.h @@ -0,0 +1,55 @@ +/* + * 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 + * 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: notify.h,v 1.14.128.2 2009/01/19 23:47:01 tbox Exp $ */ + +#ifndef NAMED_NOTIFY_H +#define NAMED_NOTIFY_H 1 + +#include +#include + +/*** + *** Module Info + ***/ + +/*! \file + * \brief + * RFC1996 + * A Mechanism for Prompt Notification of Zone Changes (DNS NOTIFY) + */ + +/*** + *** Functions. + ***/ + +void +ns_notify_start(ns_client_t *client); + +/*%< + * Examines the incoming message to determine appropriate zone. + * Returns FORMERR if there is not exactly one question. + * Returns REFUSED if we do not serve the listed zone. + * Pass the message to the zone module for processing + * and returns the return status. + * + * Requires + *\li client to be valid. + */ + +#endif /* NAMED_NOTIFY_H */ + diff --git a/contrib/bind-9.5.2/bin/named/include/named/ns_smf_globals.h b/contrib/bind-9.5.2/bin/named/include/named/ns_smf_globals.h new file mode 100644 index 0000000000..3a35743577 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/ns_smf_globals.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2005, 2007 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: ns_smf_globals.h,v 1.7 2007/06/19 23:46:59 tbox Exp $ */ + +#ifndef NS_SMF_GLOBALS_H +#define NS_SMF_GLOBALS_H 1 + +#include + +#undef EXTERN +#undef INIT +#ifdef NS_MAIN +#define EXTERN +#define INIT(v) = (v) +#else +#define EXTERN extern +#define INIT(v) +#endif + +EXTERN unsigned int ns_smf_got_instance INIT(0); +EXTERN unsigned int ns_smf_chroot INIT(0); +EXTERN unsigned int ns_smf_want_disable INIT(0); + +isc_result_t ns_smf_add_message(isc_buffer_t *text); +isc_result_t ns_smf_get_instance(char **name, int debug, isc_mem_t *mctx); + +#undef EXTERN +#undef INIT + +#endif /* NS_SMF_GLOBALS_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/query.h b/contrib/bind-9.5.2/bin/named/include/named/query.h new file mode 100644 index 0000000000..500b57714e --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/query.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2002 Internet Software Consortium. + * + * 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: query.h,v 1.40 2007/06/19 23:46:59 tbox Exp $ */ + +#ifndef NAMED_QUERY_H +#define NAMED_QUERY_H 1 + +/*! \file */ + +#include +#include +#include + +#include + +#include + +/*% nameserver database version structure */ +typedef struct ns_dbversion { + dns_db_t *db; + dns_dbversion_t *version; + isc_boolean_t queryok; + ISC_LINK(struct ns_dbversion) link; +} ns_dbversion_t; + +/*% nameserver query structure */ +struct ns_query { + unsigned int attributes; + unsigned int restarts; + isc_boolean_t timerset; + dns_name_t * qname; + dns_name_t * origqname; + unsigned int dboptions; + unsigned int fetchoptions; + dns_db_t * gluedb; + dns_db_t * authdb; + dns_zone_t * authzone; + isc_boolean_t authdbset; + isc_boolean_t isreferral; + isc_mutex_t fetchlock; + dns_fetch_t * fetch; + isc_bufferlist_t namebufs; + ISC_LIST(ns_dbversion_t) activeversions; + ISC_LIST(ns_dbversion_t) freeversions; +}; + +#define NS_QUERYATTR_RECURSIONOK 0x0001 +#define NS_QUERYATTR_CACHEOK 0x0002 +#define NS_QUERYATTR_PARTIALANSWER 0x0004 +#define NS_QUERYATTR_NAMEBUFUSED 0x0008 +#define NS_QUERYATTR_RECURSING 0x0010 +#define NS_QUERYATTR_CACHEGLUEOK 0x0020 +#define NS_QUERYATTR_QUERYOKVALID 0x0040 +#define NS_QUERYATTR_QUERYOK 0x0080 +#define NS_QUERYATTR_WANTRECURSION 0x0100 +#define NS_QUERYATTR_SECURE 0x0200 +#define NS_QUERYATTR_NOAUTHORITY 0x0400 +#define NS_QUERYATTR_NOADDITIONAL 0x0800 + +isc_result_t +ns_query_init(ns_client_t *client); + +void +ns_query_free(ns_client_t *client); + +void +ns_query_start(ns_client_t *client); + +void +ns_query_cancel(ns_client_t *client); + +#endif /* NAMED_QUERY_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/server.h b/contrib/bind-9.5.2/bin/named/include/named/server.h new file mode 100644 index 0000000000..6917acaf15 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/server.h @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2004-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 + * 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: server.h,v 1.88.10.7 2009/07/11 04:28:14 marka Exp $ */ + +#ifndef NAMED_SERVER_H +#define NAMED_SERVER_H 1 + +/*! \file */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define NS_EVENTCLASS ISC_EVENTCLASS(0x4E43) +#define NS_EVENT_RELOAD (NS_EVENTCLASS + 0) +#define NS_EVENT_CLIENTCONTROL (NS_EVENTCLASS + 1) + +/*% + * Name server state. Better here than in lots of separate global variables. + */ +struct ns_server { + unsigned int magic; + isc_mem_t * mctx; + + isc_task_t * task; + + /* Configurable data. */ + isc_quota_t xfroutquota; + isc_quota_t tcpquota; + isc_quota_t recursionquota; + dns_acl_t *blackholeacl; + char * statsfile; /*%< Statistics file name */ + char * dumpfile; /*%< Dump file name */ + char * recfile; /*%< Recursive file name */ + isc_boolean_t version_set; /*%< User has set version */ + char * version; /*%< User-specified version */ + isc_boolean_t hostname_set; /*%< User has set hostname */ + char * hostname; /*%< User-specified hostname */ + /*% Use hostname for server id */ + isc_boolean_t server_usehostname; + char * server_id; /*%< User-specified server id */ + + /*% + * Current ACL environment. This defines the + * current values of the localhost and localnets + * ACLs. + */ + dns_aclenv_t aclenv; + + /* Server data structures. */ + dns_loadmgr_t * loadmgr; + dns_zonemgr_t * zonemgr; + dns_viewlist_t viewlist; + ns_interfacemgr_t * interfacemgr; + dns_db_t * in_roothints; + dns_tkeyctx_t * tkeyctx; + + isc_timer_t * interface_timer; + isc_timer_t * heartbeat_timer; + isc_timer_t * pps_timer; + + isc_uint32_t interface_interval; + isc_uint32_t heartbeat_interval; + + isc_mutex_t reload_event_lock; + isc_event_t * reload_event; + + isc_boolean_t flushonshutdown; + isc_boolean_t log_queries; /*%< For BIND 8 compatibility */ + + isc_stats_t * nsstats; /*%< Server statistics */ + dns_stats_t * rcvquerystats; /*% Incoming query statistics */ + dns_stats_t * opcodestats; /*%< Incoming message statistics */ + isc_stats_t * zonestats; /*% Zone management statistics */ + isc_stats_t * resolverstats; /*% Resolver statistics */ + + isc_stats_t * sockstats; /*%< Socket statistics */ + ns_controls_t * controls; /*%< Control channels */ + unsigned int dispatchgen; + ns_dispatchlist_t dispatches; + + dns_acache_t *acache; + + ns_statschannellist_t statschannels; +}; + +#define NS_SERVER_MAGIC ISC_MAGIC('S','V','E','R') +#define NS_SERVER_VALID(s) ISC_MAGIC_VALID(s, NS_SERVER_MAGIC) + +/*% + * Server statistics counters. Used as isc_statscounter_t values. + */ +enum { + dns_nsstatscounter_requestv4 = 0, + dns_nsstatscounter_requestv6 = 1, + dns_nsstatscounter_edns0in = 2, + dns_nsstatscounter_badednsver = 3, + dns_nsstatscounter_tsigin = 4, + dns_nsstatscounter_sig0in = 5, + dns_nsstatscounter_invalidsig = 6, + dns_nsstatscounter_tcp = 7, + + dns_nsstatscounter_authrej = 8, + dns_nsstatscounter_recurserej = 9, + dns_nsstatscounter_xfrrej = 10, + dns_nsstatscounter_updaterej = 11, + + dns_nsstatscounter_response = 12, + dns_nsstatscounter_truncatedresp = 13, + dns_nsstatscounter_edns0out = 14, + dns_nsstatscounter_tsigout = 15, + dns_nsstatscounter_sig0out = 16, + + dns_nsstatscounter_success = 17, + dns_nsstatscounter_authans = 18, + dns_nsstatscounter_nonauthans = 19, + dns_nsstatscounter_referral = 20, + dns_nsstatscounter_nxrrset = 21, + dns_nsstatscounter_servfail = 22, + dns_nsstatscounter_formerr = 23, + dns_nsstatscounter_nxdomain = 24, + dns_nsstatscounter_recursion = 25, + dns_nsstatscounter_duplicate = 26, + dns_nsstatscounter_dropped = 27, + dns_nsstatscounter_failure = 28, + + dns_nsstatscounter_xfrdone = 29, + + dns_nsstatscounter_updatereqfwd = 30, + dns_nsstatscounter_updaterespfwd = 31, + dns_nsstatscounter_updatefwdfail = 32, + dns_nsstatscounter_updatedone = 33, + dns_nsstatscounter_updatefail = 34, + dns_nsstatscounter_updatebadprereq = 35, + + dns_nsstatscounter_max = 36 +}; + +void +ns_server_create(isc_mem_t *mctx, ns_server_t **serverp); +/*%< + * Create a server object with default settings. + * This function either succeeds or causes the program to exit + * with a fatal error. + */ + +void +ns_server_destroy(ns_server_t **serverp); +/*%< + * Destroy a server object, freeing its memory. + */ + +void +ns_server_reloadwanted(ns_server_t *server); +/*%< + * Inform a server that a reload is wanted. This function + * may be called asynchronously, from outside the server's task. + * If a reload is already scheduled or in progress, the call + * is ignored. + */ + +void +ns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush); +/*%< + * Inform the server that the zones should be flushed to disk on shutdown. + */ + +isc_result_t +ns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t *text); +/*%< + * Act on a "reload" command from the command channel. + */ + +isc_result_t +ns_server_reconfigcommand(ns_server_t *server, char *args); +/*%< + * Act on a "reconfig" command from the command channel. + */ + +isc_result_t +ns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t *text); +/*%< + * Act on a "notify" command from the command channel. + */ + +isc_result_t +ns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t *text); +/*%< + * Act on a "refresh" command from the command channel. + */ + +isc_result_t +ns_server_retransfercommand(ns_server_t *server, char *args); +/*%< + * Act on a "retransfer" command from the command channel. + */ + +isc_result_t +ns_server_togglequerylog(ns_server_t *server); +/*%< + * Toggle logging of queries, as in BIND 8. + */ + +/*% + * Dump the current statistics to the statistics file. + */ +isc_result_t +ns_server_dumpstats(ns_server_t *server); + +/*% + * Dump the current cache to the dump file. + */ +isc_result_t +ns_server_dumpdb(ns_server_t *server, char *args); + +/*% + * Change or increment the server debug level. + */ +isc_result_t +ns_server_setdebuglevel(ns_server_t *server, char *args); + +/*% + * Flush the server's cache(s) + */ +isc_result_t +ns_server_flushcache(ns_server_t *server, char *args); + +/*% + * Flush a particular name from the server's cache(s) + */ +isc_result_t +ns_server_flushname(ns_server_t *server, char *args); + +/*% + * Report the server's status. + */ +isc_result_t +ns_server_status(ns_server_t *server, isc_buffer_t *text); + +/*% + * Report a list of dynamic and static tsig keys, per view. + */ +isc_result_t +ns_server_tsiglist(ns_server_t *server, isc_buffer_t *text); + +/*% + * Delete a specific key (with optional view). + */ +isc_result_t +ns_server_tsigdelete(ns_server_t *server, char *command, isc_buffer_t *text); + +/*% + * Enable or disable updates for a zone. + */ +isc_result_t +ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args, + isc_buffer_t *text); + +/*% + * Dump the current recursive queries. + */ +isc_result_t +ns_server_dumprecursing(ns_server_t *server); + +/*% + * Maintain a list of dispatches that require reserved ports. + */ +void +ns_add_reserved_dispatch(ns_server_t *server, const isc_sockaddr_t *addr); + +/*% + * Enable or disable dnssec validation. + */ +isc_result_t +ns_server_validation(ns_server_t *server, char *args); + +#endif /* NAMED_SERVER_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/sortlist.h b/contrib/bind-9.5.2/bin/named/include/named/sortlist.h new file mode 100644 index 0000000000..b9f6076114 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/sortlist.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * 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: sortlist.h,v 1.11 2007/06/19 23:46:59 tbox Exp $ */ + +#ifndef NAMED_SORTLIST_H +#define NAMED_SORTLIST_H 1 + +/*! \file */ + +#include + +#include + +/*% + * Type for callback functions that rank addresses. + */ +typedef int +(*dns_addressorderfunc_t)(const isc_netaddr_t *address, const void *arg); + +/*% + * Return value type for setup_sortlist. + */ +typedef enum { + NS_SORTLISTTYPE_NONE, + NS_SORTLISTTYPE_1ELEMENT, + NS_SORTLISTTYPE_2ELEMENT +} ns_sortlisttype_t; + +ns_sortlisttype_t +ns_sortlist_setup(dns_acl_t *acl, isc_netaddr_t *clientaddr, + const void **argp); +/*%< + * Find the sortlist statement in 'acl' that applies to 'clientaddr', if any. + * + * If a 1-element sortlist item applies, return NS_SORTLISTTYPE_1ELEMENT and + * make '*argp' point to the matching subelement. + * + * If a 2-element sortlist item applies, return NS_SORTLISTTYPE_2ELEMENT and + * make '*argp' point to ACL that forms the second element. + * + * If no sortlist item applies, return NS_SORTLISTTYPE_NONE and set '*argp' + * to NULL. + */ + +int +ns_sortlist_addrorder1(const isc_netaddr_t *addr, const void *arg); +/*%< + * Find the sort order of 'addr' in 'arg', the matching element + * of a 1-element top-level sortlist statement. + */ + +int +ns_sortlist_addrorder2(const isc_netaddr_t *addr, const void *arg); +/*%< + * Find the sort order of 'addr' in 'arg', a topology-like + * ACL forming the second element in a 2-element top-level + * sortlist statement. + */ + +void +ns_sortlist_byaddrsetup(dns_acl_t *sortlist_acl, isc_netaddr_t *client_addr, + dns_addressorderfunc_t *orderp, + const void **argp); +/*%< + * Find the sortlist statement in 'acl' that applies to 'clientaddr', if any. + * If a sortlist statement applies, return in '*orderp' a pointer to a function + * for ranking network addresses based on that sortlist statement, and in + * '*argp' an argument to pass to said function. If no sortlist statement + * applies, set '*orderp' and '*argp' to NULL. + */ + +#endif /* NAMED_SORTLIST_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/statschannel.h b/contrib/bind-9.5.2/bin/named/include/named/statschannel.h new file mode 100644 index 0000000000..da89423dbf --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/statschannel.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2008 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: statschannel.h,v 1.2.2.2 2008/04/03 06:10:19 marka Exp $ */ + +#ifndef NAMED_STATSCHANNEL_H +#define NAMED_STATSCHANNEL_H 1 + +/*! \file + * \brief + * The statistics channels built-in the name server. + */ + +#include + +#include + +#include + +#define NS_STATSCHANNEL_HTTPPORT 80 + +isc_result_t +ns_statschannels_configure(ns_server_t *server, const cfg_obj_t *config, + cfg_aclconfctx_t *aclconfctx); +/*%< + * [Re]configure the statistics channels. + * + * If it is no longer there but was previously configured, destroy + * it here. + * + * If the IP address or port has changed, destroy the old server + * and create a new one. + */ + + +void +ns_statschannels_shutdown(ns_server_t *server); +/*%< + * Initiate shutdown of all the statistics channel listeners. + */ + +isc_result_t +ns_stats_dump(ns_server_t *server, FILE *fp); +/*%< + * Dump statistics counters managed by the server to the file fp. + */ + +#endif /* NAMED_STATSCHANNEL_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/tkeyconf.h b/contrib/bind-9.5.2/bin/named/include/named/tkeyconf.h new file mode 100644 index 0000000000..02bd71883a --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/tkeyconf.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * 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: tkeyconf.h,v 1.16 2007/06/19 23:46:59 tbox Exp $ */ + +#ifndef NS_TKEYCONF_H +#define NS_TKEYCONF_H 1 + +/*! \file */ + +#include +#include + +#include + +ISC_LANG_BEGINDECLS + +isc_result_t +ns_tkeyctx_fromconfig(const cfg_obj_t *options, isc_mem_t *mctx, + isc_entropy_t *ectx, dns_tkeyctx_t **tctxp); +/*%< + * Create a TKEY context and configure it, including the default DH key + * and default domain, according to 'options'. + * + * Requires: + *\li 'cfg' is a valid configuration options object. + *\li 'mctx' is not NULL + *\li 'ectx' is not NULL + *\li 'tctx' is not NULL + *\li '*tctx' is NULL + * + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_NOMEMORY + */ + +ISC_LANG_ENDDECLS + +#endif /* NS_TKEYCONF_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/tsigconf.h b/contrib/bind-9.5.2/bin/named/include/named/tsigconf.h new file mode 100644 index 0000000000..49ad82af39 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/tsigconf.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * 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: tsigconf.h,v 1.16 2007/06/19 23:46:59 tbox Exp $ */ + +#ifndef NS_TSIGCONF_H +#define NS_TSIGCONF_H 1 + +/*! \file */ + +#include +#include + +ISC_LANG_BEGINDECLS + +isc_result_t +ns_tsigkeyring_fromconfig(const cfg_obj_t *config, const cfg_obj_t *vconfig, + isc_mem_t *mctx, dns_tsig_keyring_t **ringp); +/*%< + * Create a TSIG key ring and configure it according to the 'key' + * statements in the global and view configuration objects. + * + * Requires: + * \li 'config' is not NULL. + * \li 'mctx' is not NULL + * \li 'ring' is not NULL, and '*ring' is NULL + * + * Returns: + * \li ISC_R_SUCCESS + * \li ISC_R_NOMEMORY + */ + +ISC_LANG_ENDDECLS + +#endif /* NS_TSIGCONF_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/types.h b/contrib/bind-9.5.2/bin/named/include/named/types.h new file mode 100644 index 0000000000..ca1468717f --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/types.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * 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.27.128.2 2008/01/17 23:46:36 tbox Exp $ */ + +#ifndef NAMED_TYPES_H +#define NAMED_TYPES_H 1 + +/*! \file */ + +#include + +typedef struct ns_client ns_client_t; +typedef struct ns_clientmgr ns_clientmgr_t; +typedef struct ns_query ns_query_t; +typedef struct ns_server ns_server_t; +typedef struct ns_xmld ns_xmld_t; +typedef struct ns_xmldmgr ns_xmldmgr_t; +typedef struct ns_interface ns_interface_t; +typedef struct ns_interfacemgr ns_interfacemgr_t; +typedef struct ns_lwresd ns_lwresd_t; +typedef struct ns_lwreslistener ns_lwreslistener_t; +typedef struct ns_lwdclient ns_lwdclient_t; +typedef struct ns_lwdclientmgr ns_lwdclientmgr_t; +typedef struct ns_lwsearchlist ns_lwsearchlist_t; +typedef struct ns_lwsearchctx ns_lwsearchctx_t; +typedef struct ns_controls ns_controls_t; +typedef struct ns_dispatch ns_dispatch_t; +typedef ISC_LIST(ns_dispatch_t) ns_dispatchlist_t; +typedef struct ns_statschannel ns_statschannel_t; +typedef ISC_LIST(ns_statschannel_t) ns_statschannellist_t; +#endif /* NAMED_TYPES_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/update.h b/contrib/bind-9.5.2/bin/named/include/named/update.h new file mode 100644 index 0000000000..a34570c2f5 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/update.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * 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: update.h,v 1.13 2007/06/19 23:46:59 tbox Exp $ */ + +#ifndef NAMED_UPDATE_H +#define NAMED_UPDATE_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file + * \brief + * RFC2136 Dynamic Update + */ + +/*** + *** Imports + ***/ + +#include +#include + +/*** + *** Types. + ***/ + +/*** + *** Functions + ***/ + +void +ns_update_start(ns_client_t *client, isc_result_t sigresult); + +#endif /* NAMED_UPDATE_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/xfrout.h b/contrib/bind-9.5.2/bin/named/include/named/xfrout.h new file mode 100644 index 0000000000..4bb79a31e9 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/xfrout.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * 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: xfrout.h,v 1.12 2007/06/19 23:46:59 tbox Exp $ */ + +#ifndef NAMED_XFROUT_H +#define NAMED_XFROUT_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file + * \brief + * Outgoing zone transfers (AXFR + IXFR). + */ + +/*** + *** Functions + ***/ + +void +ns_xfr_start(ns_client_t *client, dns_rdatatype_t xfrtype); + +#endif /* NAMED_XFROUT_H */ diff --git a/contrib/bind-9.5.2/bin/named/include/named/zoneconf.h b/contrib/bind-9.5.2/bin/named/include/named/zoneconf.h new file mode 100644 index 0000000000..b973013c22 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/include/named/zoneconf.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2002 Internet Software Consortium. + * + * 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: zoneconf.h,v 1.26 2007/06/19 23:46:59 tbox Exp $ */ + +#ifndef NS_ZONECONF_H +#define NS_ZONECONF_H 1 + +/*! \file */ + +#include +#include + +#include +#include + +ISC_LANG_BEGINDECLS + +isc_result_t +ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, + const cfg_obj_t *zconfig, cfg_aclconfctx_t *ac, + dns_zone_t *zone); +/*%< + * Configure or reconfigure a zone according to the named.conf + * data in 'cctx' and 'czone'. + * + * The zone origin is not configured, it is assumed to have been set + * at zone creation time. + * + * Require: + * \li 'lctx' to be initialized or NULL. + * \li 'cctx' to be initialized or NULL. + * \li 'ac' to point to an initialized ns_aclconfctx_t. + * \li 'czone' to be initialized. + * \li 'zone' to be initialized. + */ + +isc_boolean_t +ns_zone_reusable(dns_zone_t *zone, const cfg_obj_t *zconfig); +/*%< + * If 'zone' can be safely reconfigured according to the configuration + * data in 'zconfig', return ISC_TRUE. If the configuration data is so + * different from the current zone state that the zone needs to be destroyed + * and recreated, return ISC_FALSE. + */ + +ISC_LANG_ENDDECLS + +#endif /* NS_ZONECONF_H */ diff --git a/contrib/bind-9.5.2/bin/named/interfacemgr.c b/contrib/bind-9.5.2/bin/named/interfacemgr.c new file mode 100644 index 0000000000..3f16baf68e --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/interfacemgr.c @@ -0,0 +1,974 @@ +/* + * 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 + * 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: interfacemgr.c,v 1.90.64.5 2009/01/19 23:47:01 tbox Exp $ */ + +/*! \file */ + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#define IFMGR_MAGIC ISC_MAGIC('I', 'F', 'M', 'G') +#define NS_INTERFACEMGR_VALID(t) ISC_MAGIC_VALID(t, IFMGR_MAGIC) + +#define IFMGR_COMMON_LOGARGS \ + ns_g_lctx, NS_LOGCATEGORY_NETWORK, NS_LOGMODULE_INTERFACEMGR + +/*% nameserver interface manager structure */ +struct ns_interfacemgr { + unsigned int magic; /*%< Magic number. */ + int references; + isc_mutex_t lock; + isc_mem_t * mctx; /*%< Memory context. */ + isc_taskmgr_t * taskmgr; /*%< Task manager. */ + isc_socketmgr_t * socketmgr; /*%< Socket manager. */ + dns_dispatchmgr_t * dispatchmgr; + unsigned int generation; /*%< Current generation no. */ + ns_listenlist_t * listenon4; + ns_listenlist_t * listenon6; + dns_aclenv_t aclenv; /*%< Localhost/localnets ACLs */ + ISC_LIST(ns_interface_t) interfaces; /*%< List of interfaces. */ + ISC_LIST(isc_sockaddr_t) listenon; +}; + +static void +purge_old_interfaces(ns_interfacemgr_t *mgr); + +static void +clearlistenon(ns_interfacemgr_t *mgr); + +isc_result_t +ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, + isc_socketmgr_t *socketmgr, + dns_dispatchmgr_t *dispatchmgr, + ns_interfacemgr_t **mgrp) +{ + isc_result_t result; + ns_interfacemgr_t *mgr; + + REQUIRE(mctx != NULL); + REQUIRE(mgrp != NULL); + REQUIRE(*mgrp == NULL); + + mgr = isc_mem_get(mctx, sizeof(*mgr)); + if (mgr == NULL) + return (ISC_R_NOMEMORY); + + result = isc_mutex_init(&mgr->lock); + if (result != ISC_R_SUCCESS) + goto cleanup_mem; + + mgr->mctx = mctx; + mgr->taskmgr = taskmgr; + mgr->socketmgr = socketmgr; + mgr->dispatchmgr = dispatchmgr; + mgr->generation = 1; + mgr->listenon4 = NULL; + mgr->listenon6 = NULL; + + ISC_LIST_INIT(mgr->interfaces); + ISC_LIST_INIT(mgr->listenon); + + /* + * The listen-on lists are initially empty. + */ + result = ns_listenlist_create(mctx, &mgr->listenon4); + if (result != ISC_R_SUCCESS) + goto cleanup_mem; + ns_listenlist_attach(mgr->listenon4, &mgr->listenon6); + + result = dns_aclenv_init(mctx, &mgr->aclenv); + if (result != ISC_R_SUCCESS) + goto cleanup_listenon; + + mgr->references = 1; + mgr->magic = IFMGR_MAGIC; + *mgrp = mgr; + return (ISC_R_SUCCESS); + + cleanup_listenon: + ns_listenlist_detach(&mgr->listenon4); + ns_listenlist_detach(&mgr->listenon6); + cleanup_mem: + isc_mem_put(mctx, mgr, sizeof(*mgr)); + return (result); +} + +static void +ns_interfacemgr_destroy(ns_interfacemgr_t *mgr) { + REQUIRE(NS_INTERFACEMGR_VALID(mgr)); + dns_aclenv_destroy(&mgr->aclenv); + ns_listenlist_detach(&mgr->listenon4); + ns_listenlist_detach(&mgr->listenon6); + clearlistenon(mgr); + DESTROYLOCK(&mgr->lock); + mgr->magic = 0; + isc_mem_put(mgr->mctx, mgr, sizeof(*mgr)); +} + +dns_aclenv_t * +ns_interfacemgr_getaclenv(ns_interfacemgr_t *mgr) { + return (&mgr->aclenv); +} + +void +ns_interfacemgr_attach(ns_interfacemgr_t *source, ns_interfacemgr_t **target) { + REQUIRE(NS_INTERFACEMGR_VALID(source)); + LOCK(&source->lock); + INSIST(source->references > 0); + source->references++; + UNLOCK(&source->lock); + *target = source; +} + +void +ns_interfacemgr_detach(ns_interfacemgr_t **targetp) { + isc_result_t need_destroy = ISC_FALSE; + ns_interfacemgr_t *target = *targetp; + REQUIRE(target != NULL); + REQUIRE(NS_INTERFACEMGR_VALID(target)); + LOCK(&target->lock); + REQUIRE(target->references > 0); + target->references--; + if (target->references == 0) + need_destroy = ISC_TRUE; + UNLOCK(&target->lock); + if (need_destroy) + ns_interfacemgr_destroy(target); + *targetp = NULL; +} + +void +ns_interfacemgr_shutdown(ns_interfacemgr_t *mgr) { + REQUIRE(NS_INTERFACEMGR_VALID(mgr)); + + /*% + * Shut down and detach all interfaces. + * By incrementing the generation count, we make purge_old_interfaces() + * consider all interfaces "old". + */ + mgr->generation++; + purge_old_interfaces(mgr); +} + + +static isc_result_t +ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, + const char *name, ns_interface_t **ifpret) +{ + ns_interface_t *ifp; + isc_result_t result; + + REQUIRE(NS_INTERFACEMGR_VALID(mgr)); + ifp = isc_mem_get(mgr->mctx, sizeof(*ifp)); + if (ifp == NULL) + return (ISC_R_NOMEMORY); + ifp->mgr = NULL; + ifp->generation = mgr->generation; + ifp->addr = *addr; + ifp->flags = 0; + strncpy(ifp->name, name, sizeof(ifp->name)); + ifp->name[sizeof(ifp->name)-1] = '\0'; + ifp->clientmgr = NULL; + + result = isc_mutex_init(&ifp->lock); + if (result != ISC_R_SUCCESS) + goto lock_create_failure; + + result = ns_clientmgr_create(mgr->mctx, mgr->taskmgr, + ns_g_timermgr, + &ifp->clientmgr); + if (result != ISC_R_SUCCESS) { + isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, + "ns_clientmgr_create() failed: %s", + isc_result_totext(result)); + goto clientmgr_create_failure; + } + + ifp->udpdispatch = NULL; + + ifp->tcpsocket = NULL; + /* + * Create a single TCP client object. It will replace itself + * with a new one as soon as it gets a connection, so the actual + * connections will be handled in parallel even though there is + * only one client initially. + */ + ifp->ntcptarget = 1; + ifp->ntcpcurrent = 0; + + ISC_LINK_INIT(ifp, link); + + ns_interfacemgr_attach(mgr, &ifp->mgr); + ISC_LIST_APPEND(mgr->interfaces, ifp, link); + + ifp->references = 1; + ifp->magic = IFACE_MAGIC; + *ifpret = ifp; + + return (ISC_R_SUCCESS); + + clientmgr_create_failure: + DESTROYLOCK(&ifp->lock); + lock_create_failure: + ifp->magic = 0; + isc_mem_put(mgr->mctx, ifp, sizeof(*ifp)); + + return (ISC_R_UNEXPECTED); +} + +static isc_result_t +ns_interface_listenudp(ns_interface_t *ifp) { + isc_result_t result; + unsigned int attrs; + unsigned int attrmask; + + attrs = 0; + attrs |= DNS_DISPATCHATTR_UDP; + if (isc_sockaddr_pf(&ifp->addr) == AF_INET) + attrs |= DNS_DISPATCHATTR_IPV4; + else + attrs |= DNS_DISPATCHATTR_IPV6; + attrs |= DNS_DISPATCHATTR_NOLISTEN; + attrmask = 0; + attrmask |= DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP; + attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6; + result = dns_dispatch_getudp(ifp->mgr->dispatchmgr, ns_g_socketmgr, + ns_g_taskmgr, &ifp->addr, + 4096, 1000, 32768, 8219, 8237, + attrs, attrmask, &ifp->udpdispatch); + if (result != ISC_R_SUCCESS) { + isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, + "could not listen on UDP socket: %s", + isc_result_totext(result)); + goto udp_dispatch_failure; + } + + result = ns_clientmgr_createclients(ifp->clientmgr, ns_g_cpus, + ifp, ISC_FALSE); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "UDP ns_clientmgr_createclients(): %s", + isc_result_totext(result)); + goto addtodispatch_failure; + } + return (ISC_R_SUCCESS); + + addtodispatch_failure: + dns_dispatch_changeattributes(ifp->udpdispatch, 0, + DNS_DISPATCHATTR_NOLISTEN); + dns_dispatch_detach(&ifp->udpdispatch); + udp_dispatch_failure: + return (result); +} + +static isc_result_t +ns_interface_accepttcp(ns_interface_t *ifp) { + isc_result_t result; + + /* + * Open a TCP socket. + */ + result = isc_socket_create(ifp->mgr->socketmgr, + isc_sockaddr_pf(&ifp->addr), + isc_sockettype_tcp, + &ifp->tcpsocket); + if (result != ISC_R_SUCCESS) { + isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, + "creating TCP socket: %s", + isc_result_totext(result)); + goto tcp_socket_failure; + } + isc_socket_setname(ifp->tcpsocket, "dispatcher", NULL); +#ifndef ISC_ALLOW_MAPPED + isc_socket_ipv6only(ifp->tcpsocket, ISC_TRUE); +#endif + result = isc_socket_bind(ifp->tcpsocket, &ifp->addr, + ISC_SOCKET_REUSEADDRESS); + if (result != ISC_R_SUCCESS) { + isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, + "binding TCP socket: %s", + isc_result_totext(result)); + goto tcp_bind_failure; + } + result = isc_socket_listen(ifp->tcpsocket, ns_g_listen); + if (result != ISC_R_SUCCESS) { + isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, + "listening on TCP socket: %s", + isc_result_totext(result)); + goto tcp_listen_failure; + } + + /* + * If/when there a multiple filters listen to the + * result. + */ + (void)isc_socket_filter(ifp->tcpsocket, "dataready"); + + result = ns_clientmgr_createclients(ifp->clientmgr, + ifp->ntcptarget, ifp, + ISC_TRUE); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "TCP ns_clientmgr_createclients(): %s", + isc_result_totext(result)); + goto accepttcp_failure; + } + return (ISC_R_SUCCESS); + + accepttcp_failure: + tcp_listen_failure: + tcp_bind_failure: + isc_socket_detach(&ifp->tcpsocket); + tcp_socket_failure: + return (ISC_R_SUCCESS); +} + +static isc_result_t +ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, + const char *name, ns_interface_t **ifpret, + isc_boolean_t accept_tcp) +{ + isc_result_t result; + ns_interface_t *ifp = NULL; + REQUIRE(ifpret != NULL && *ifpret == NULL); + + result = ns_interface_create(mgr, addr, name, &ifp); + if (result != ISC_R_SUCCESS) + return (result); + + result = ns_interface_listenudp(ifp); + if (result != ISC_R_SUCCESS) + goto cleanup_interface; + + if (accept_tcp == ISC_TRUE) { + result = ns_interface_accepttcp(ifp); + if (result != ISC_R_SUCCESS) { + /* + * XXXRTH We don't currently have a way to easily stop + * dispatch service, so we currently return + * ISC_R_SUCCESS (the UDP stuff will work even if TCP + * creation failed). This will be fixed later. + */ + result = ISC_R_SUCCESS; + } + } + *ifpret = ifp; + return (ISC_R_SUCCESS); + + cleanup_interface: + ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link); + ns_interface_detach(&ifp); + return (result); +} + +void +ns_interface_shutdown(ns_interface_t *ifp) { + if (ifp->clientmgr != NULL) + ns_clientmgr_destroy(&ifp->clientmgr); +} + +static void +ns_interface_destroy(ns_interface_t *ifp) { + isc_mem_t *mctx = ifp->mgr->mctx; + REQUIRE(NS_INTERFACE_VALID(ifp)); + + ns_interface_shutdown(ifp); + + if (ifp->udpdispatch != NULL) { + dns_dispatch_changeattributes(ifp->udpdispatch, 0, + DNS_DISPATCHATTR_NOLISTEN); + dns_dispatch_detach(&ifp->udpdispatch); + } + if (ifp->tcpsocket != NULL) + isc_socket_detach(&ifp->tcpsocket); + + DESTROYLOCK(&ifp->lock); + + ns_interfacemgr_detach(&ifp->mgr); + + ifp->magic = 0; + isc_mem_put(mctx, ifp, sizeof(*ifp)); +} + +void +ns_interface_attach(ns_interface_t *source, ns_interface_t **target) { + REQUIRE(NS_INTERFACE_VALID(source)); + LOCK(&source->lock); + INSIST(source->references > 0); + source->references++; + UNLOCK(&source->lock); + *target = source; +} + +void +ns_interface_detach(ns_interface_t **targetp) { + isc_result_t need_destroy = ISC_FALSE; + ns_interface_t *target = *targetp; + REQUIRE(target != NULL); + REQUIRE(NS_INTERFACE_VALID(target)); + LOCK(&target->lock); + REQUIRE(target->references > 0); + target->references--; + if (target->references == 0) + need_destroy = ISC_TRUE; + UNLOCK(&target->lock); + if (need_destroy) + ns_interface_destroy(target); + *targetp = NULL; +} + +/*% + * Search the interface list for an interface whose address and port + * both match those of 'addr'. Return a pointer to it, or NULL if not found. + */ +static ns_interface_t * +find_matching_interface(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) { + ns_interface_t *ifp; + for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL; + ifp = ISC_LIST_NEXT(ifp, link)) { + if (isc_sockaddr_equal(&ifp->addr, addr)) + break; + } + return (ifp); +} + +/*% + * Remove any interfaces whose generation number is not the current one. + */ +static void +purge_old_interfaces(ns_interfacemgr_t *mgr) { + ns_interface_t *ifp, *next; + for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL; ifp = next) { + INSIST(NS_INTERFACE_VALID(ifp)); + next = ISC_LIST_NEXT(ifp, link); + if (ifp->generation != mgr->generation) { + char sabuf[256]; + ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link); + isc_sockaddr_format(&ifp->addr, sabuf, sizeof(sabuf)); + isc_log_write(IFMGR_COMMON_LOGARGS, + ISC_LOG_INFO, + "no longer listening on %s", sabuf); + ns_interface_shutdown(ifp); + ns_interface_detach(&ifp); + } + } +} + +static isc_result_t +clearacl(isc_mem_t *mctx, dns_acl_t **aclp) { + dns_acl_t *newacl = NULL; + isc_result_t result; + result = dns_acl_create(mctx, 0, &newacl); + if (result != ISC_R_SUCCESS) + return (result); + dns_acl_detach(aclp); + dns_acl_attach(newacl, aclp); + dns_acl_detach(&newacl); + return (ISC_R_SUCCESS); +} + +static isc_boolean_t +listenon_is_ip6_any(ns_listenelt_t *elt) { + REQUIRE(elt && elt->acl); + return dns_acl_isany(elt->acl); +} + +static isc_result_t +setup_locals(ns_interfacemgr_t *mgr, isc_interface_t *interface) { + isc_result_t result; + unsigned int prefixlen; + isc_netaddr_t *netaddr; + + netaddr = &interface->address; + + /* First add localhost address */ + prefixlen = (netaddr->family == AF_INET) ? 32 : 128; + result = dns_iptable_addprefix(mgr->aclenv.localhost->iptable, + netaddr, prefixlen, ISC_TRUE); + if (result != ISC_R_SUCCESS) + return (result); + + /* Then add localnets prefix */ + result = isc_netaddr_masktoprefixlen(&interface->netmask, + &prefixlen); + + /* Non contiguous netmasks not allowed by IPv6 arch. */ + if (result != ISC_R_SUCCESS && netaddr->family == AF_INET6) + return (result); + + if (result != ISC_R_SUCCESS) { + isc_log_write(IFMGR_COMMON_LOGARGS, + ISC_LOG_WARNING, + "omitting IPv4 interface %s from " + "localnets ACL: %s", + interface->name, + isc_result_totext(result)); + return (ISC_R_SUCCESS); + } + + result = dns_iptable_addprefix(mgr->aclenv.localnets->iptable, + netaddr, prefixlen, ISC_TRUE); + if (result != ISC_R_SUCCESS) + return (result); + + return (ISC_R_SUCCESS); +} + +static void +setup_listenon(ns_interfacemgr_t *mgr, isc_interface_t *interface, + in_port_t port) +{ + isc_sockaddr_t *addr; + isc_sockaddr_t *old; + + addr = isc_mem_get(mgr->mctx, sizeof(*addr)); + if (addr == NULL) + return; + + isc_sockaddr_fromnetaddr(addr, &interface->address, port); + + for (old = ISC_LIST_HEAD(mgr->listenon); + old != NULL; + old = ISC_LIST_NEXT(old, link)) + if (isc_sockaddr_equal(addr, old)) + break; + + if (old != NULL) + isc_mem_put(mgr->mctx, addr, sizeof(*addr)); + else + ISC_LIST_APPEND(mgr->listenon, addr, link); +} + +static void +clearlistenon(ns_interfacemgr_t *mgr) { + isc_sockaddr_t *old; + + old = ISC_LIST_HEAD(mgr->listenon); + while (old != NULL) { + ISC_LIST_UNLINK(mgr->listenon, old, link); + isc_mem_put(mgr->mctx, old, sizeof(*old)); + old = ISC_LIST_HEAD(mgr->listenon); + } +} + +static isc_result_t +do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen, + isc_boolean_t verbose) +{ + isc_interfaceiter_t *iter = NULL; + isc_boolean_t scan_ipv4 = ISC_FALSE; + isc_boolean_t scan_ipv6 = ISC_FALSE; + isc_boolean_t adjusting = ISC_FALSE; + isc_boolean_t ipv6only = ISC_TRUE; + isc_boolean_t ipv6pktinfo = ISC_TRUE; + isc_result_t result; + isc_netaddr_t zero_address, zero_address6; + ns_listenelt_t *le; + isc_sockaddr_t listen_addr; + ns_interface_t *ifp; + isc_boolean_t log_explicit = ISC_FALSE; + isc_boolean_t dolistenon; + + if (ext_listen != NULL) + adjusting = ISC_TRUE; + + if (isc_net_probeipv6() == ISC_R_SUCCESS) + scan_ipv6 = ISC_TRUE; +#ifdef WANT_IPV6 + else + isc_log_write(IFMGR_COMMON_LOGARGS, + verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1), + "no IPv6 interfaces found"); +#endif + + if (isc_net_probeipv4() == ISC_R_SUCCESS) + scan_ipv4 = ISC_TRUE; + else + isc_log_write(IFMGR_COMMON_LOGARGS, + verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1), + "no IPv4 interfaces found"); + + /* + * A special, but typical case; listen-on-v6 { any; }. + * When we can make the socket IPv6-only, open a single wildcard + * socket for IPv6 communication. Otherwise, make separate socket + * for each IPv6 address in order to avoid accepting IPv4 packets + * as the form of mapped addresses unintentionally unless explicitly + * allowed. + */ +#ifndef ISC_ALLOW_MAPPED + if (scan_ipv6 == ISC_TRUE && + isc_net_probe_ipv6only() != ISC_R_SUCCESS) { + ipv6only = ISC_FALSE; + log_explicit = ISC_TRUE; + } +#endif + if (scan_ipv6 == ISC_TRUE && + isc_net_probe_ipv6pktinfo() != ISC_R_SUCCESS) { + ipv6pktinfo = ISC_FALSE; + log_explicit = ISC_TRUE; + } + if (scan_ipv6 == ISC_TRUE && ipv6only && ipv6pktinfo) { + for (le = ISC_LIST_HEAD(mgr->listenon6->elts); + le != NULL; + le = ISC_LIST_NEXT(le, link)) { + struct in6_addr in6a; + + if (!listenon_is_ip6_any(le)) + continue; + + in6a = in6addr_any; + isc_sockaddr_fromin6(&listen_addr, &in6a, le->port); + + ifp = find_matching_interface(mgr, &listen_addr); + if (ifp != NULL) { + ifp->generation = mgr->generation; + } else { + isc_log_write(IFMGR_COMMON_LOGARGS, + ISC_LOG_INFO, + "listening on IPv6 " + "interfaces, port %u", + le->port); + result = ns_interface_setup(mgr, &listen_addr, + "", &ifp, + ISC_TRUE); + if (result == ISC_R_SUCCESS) + ifp->flags |= NS_INTERFACEFLAG_ANYADDR; + else + isc_log_write(IFMGR_COMMON_LOGARGS, + ISC_LOG_ERROR, + "listening on all IPv6 " + "interfaces failed"); + /* Continue. */ + } + } + } + + isc_netaddr_any(&zero_address); + isc_netaddr_any6(&zero_address6); + + result = isc_interfaceiter_create(mgr->mctx, &iter); + if (result != ISC_R_SUCCESS) + return (result); + + if (adjusting == ISC_FALSE) { + result = clearacl(mgr->mctx, &mgr->aclenv.localhost); + if (result != ISC_R_SUCCESS) + goto cleanup_iter; + result = clearacl(mgr->mctx, &mgr->aclenv.localnets); + if (result != ISC_R_SUCCESS) + goto cleanup_iter; + clearlistenon(mgr); + } + + for (result = isc_interfaceiter_first(iter); + result == ISC_R_SUCCESS; + result = isc_interfaceiter_next(iter)) + { + isc_interface_t interface; + ns_listenlist_t *ll; + unsigned int family; + + result = isc_interfaceiter_current(iter, &interface); + if (result != ISC_R_SUCCESS) + break; + + family = interface.address.family; + if (family != AF_INET && family != AF_INET6) + continue; + if (scan_ipv4 == ISC_FALSE && family == AF_INET) + continue; + if (scan_ipv6 == ISC_FALSE && family == AF_INET6) + continue; + + /* + * Test for the address being nonzero rather than testing + * INTERFACE_F_UP, because on some systems the latter + * follows the media state and we could end up ignoring + * the interface for an entire rescan interval due to + * a temporary media glitch at rescan time. + */ + if (family == AF_INET && + isc_netaddr_equal(&interface.address, &zero_address)) { + continue; + } + if (family == AF_INET6 && + isc_netaddr_equal(&interface.address, &zero_address6)) { + continue; + } + + if (adjusting == ISC_FALSE) { + result = setup_locals(mgr, &interface); + if (result != ISC_R_SUCCESS) + goto ignore_interface; + } + + ll = (family == AF_INET) ? mgr->listenon4 : mgr->listenon6; + dolistenon = ISC_TRUE; + for (le = ISC_LIST_HEAD(ll->elts); + le != NULL; + le = ISC_LIST_NEXT(le, link)) + { + int match; + isc_boolean_t ipv6_wildcard = ISC_FALSE; + isc_netaddr_t listen_netaddr; + isc_sockaddr_t listen_sockaddr; + + /* + * Construct a socket address for this IP/port + * combination. + */ + if (family == AF_INET) { + isc_netaddr_fromin(&listen_netaddr, + &interface.address.type.in); + } else { + isc_netaddr_fromin6(&listen_netaddr, + &interface.address.type.in6); + isc_netaddr_setzone(&listen_netaddr, + interface.address.zone); + } + isc_sockaddr_fromnetaddr(&listen_sockaddr, + &listen_netaddr, + le->port); + + /* + * See if the address matches the listen-on statement; + * if not, ignore the interface. + */ + (void)dns_acl_match(&listen_netaddr, NULL, le->acl, + &mgr->aclenv, &match, NULL); + if (match <= 0) + continue; + + if (adjusting == ISC_FALSE && dolistenon == ISC_TRUE) { + setup_listenon(mgr, &interface, le->port); + dolistenon = ISC_FALSE; + } + + /* + * The case of "any" IPv6 address will require + * special considerations later, so remember it. + */ + if (family == AF_INET6 && ipv6only && ipv6pktinfo && + listenon_is_ip6_any(le)) + ipv6_wildcard = ISC_TRUE; + + /* + * When adjusting interfaces with extra a listening + * list, see if the address matches the extra list. + * If it does, and is also covered by a wildcard + * interface, we need to listen on the address + * explicitly. + */ + if (adjusting == ISC_TRUE) { + ns_listenelt_t *ele; + + match = 0; + for (ele = ISC_LIST_HEAD(ext_listen->elts); + ele != NULL; + ele = ISC_LIST_NEXT(ele, link)) { + (void)dns_acl_match(&listen_netaddr, + NULL, ele->acl, + NULL, &match, NULL); + if (match > 0 && + (ele->port == le->port || + ele->port == 0)) + break; + else + match = 0; + } + if (ipv6_wildcard == ISC_TRUE && match == 0) + continue; + } + + ifp = find_matching_interface(mgr, &listen_sockaddr); + if (ifp != NULL) { + ifp->generation = mgr->generation; + } else { + char sabuf[ISC_SOCKADDR_FORMATSIZE]; + + if (adjusting == ISC_FALSE && + ipv6_wildcard == ISC_TRUE) + continue; + + if (log_explicit && family == AF_INET6 && + !adjusting && listenon_is_ip6_any(le)) { + isc_log_write(IFMGR_COMMON_LOGARGS, + verbose ? ISC_LOG_INFO : + ISC_LOG_DEBUG(1), + "IPv6 socket API is " + "incomplete; explicitly " + "binding to each IPv6 " + "address separately"); + log_explicit = ISC_FALSE; + } + isc_sockaddr_format(&listen_sockaddr, + sabuf, sizeof(sabuf)); + isc_log_write(IFMGR_COMMON_LOGARGS, + ISC_LOG_INFO, + "%s" + "listening on %s interface " + "%s, %s", + (adjusting == ISC_TRUE) ? + "additionally " : "", + (family == AF_INET) ? + "IPv4" : "IPv6", + interface.name, sabuf); + + result = ns_interface_setup(mgr, + &listen_sockaddr, + interface.name, + &ifp, + (adjusting == ISC_TRUE) ? + ISC_FALSE : + ISC_TRUE); + + if (result != ISC_R_SUCCESS) { + isc_log_write(IFMGR_COMMON_LOGARGS, + ISC_LOG_ERROR, + "creating %s interface " + "%s failed; interface " + "ignored", + (family == AF_INET) ? + "IPv4" : "IPv6", + interface.name); + } + /* Continue. */ + } + + } + continue; + + ignore_interface: + isc_log_write(IFMGR_COMMON_LOGARGS, + ISC_LOG_ERROR, + "ignoring %s interface %s: %s", + (family == AF_INET) ? "IPv4" : "IPv6", + interface.name, isc_result_totext(result)); + continue; + } + if (result != ISC_R_NOMORE) + UNEXPECTED_ERROR(__FILE__, __LINE__, + "interface iteration failed: %s", + isc_result_totext(result)); + else + result = ISC_R_SUCCESS; + cleanup_iter: + isc_interfaceiter_destroy(&iter); + return (result); +} + +static void +ns_interfacemgr_scan0(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen, + isc_boolean_t verbose) +{ + isc_boolean_t purge = ISC_TRUE; + + REQUIRE(NS_INTERFACEMGR_VALID(mgr)); + + mgr->generation++; /* Increment the generation count. */ + + if (do_scan(mgr, ext_listen, verbose) != ISC_R_SUCCESS) + purge = ISC_FALSE; + + /* + * Now go through the interface list and delete anything that + * does not have the current generation number. This is + * how we catch interfaces that go away or change their + * addresses. + */ + if (purge) + purge_old_interfaces(mgr); + + /* + * Warn if we are not listening on any interface, unless + * we're in lwresd-only mode, in which case that is to + * be expected. + */ + if (ext_listen == NULL && + ISC_LIST_EMPTY(mgr->interfaces) && ! ns_g_lwresdonly) { + isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING, + "not listening on any interfaces"); + } +} + +void +ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) { + ns_interfacemgr_scan0(mgr, NULL, verbose); +} + +void +ns_interfacemgr_adjust(ns_interfacemgr_t *mgr, ns_listenlist_t *list, + isc_boolean_t verbose) +{ + ns_interfacemgr_scan0(mgr, list, verbose); +} + +void +ns_interfacemgr_setlistenon4(ns_interfacemgr_t *mgr, ns_listenlist_t *value) { + LOCK(&mgr->lock); + ns_listenlist_detach(&mgr->listenon4); + ns_listenlist_attach(value, &mgr->listenon4); + UNLOCK(&mgr->lock); +} + +void +ns_interfacemgr_setlistenon6(ns_interfacemgr_t *mgr, ns_listenlist_t *value) { + LOCK(&mgr->lock); + ns_listenlist_detach(&mgr->listenon6); + ns_listenlist_attach(value, &mgr->listenon6); + UNLOCK(&mgr->lock); +} + +void +ns_interfacemgr_dumprecursing(FILE *f, ns_interfacemgr_t *mgr) { + ns_interface_t *interface; + + LOCK(&mgr->lock); + interface = ISC_LIST_HEAD(mgr->interfaces); + while (interface != NULL) { + if (interface->clientmgr != NULL) + ns_client_dumprecursing(f, interface->clientmgr); + interface = ISC_LIST_NEXT(interface, link); + } + UNLOCK(&mgr->lock); +} + +isc_boolean_t +ns_interfacemgr_listeningon(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) { + isc_sockaddr_t *old; + + old = ISC_LIST_HEAD(mgr->listenon); + for (old = ISC_LIST_HEAD(mgr->listenon); + old != NULL; + old = ISC_LIST_NEXT(old, link)) + if (isc_sockaddr_equal(old, addr)) + return (ISC_TRUE); + return (ISC_FALSE); +} diff --git a/contrib/bind-9.5.2/bin/named/listenlist.c b/contrib/bind-9.5.2/bin/named/listenlist.c new file mode 100644 index 0000000000..513fe9c70b --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/listenlist.c @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * 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: listenlist.c,v 1.14 2007/06/19 23:46:59 tbox Exp $ */ + +/*! \file */ + +#include + +#include +#include + +#include + +#include + +static void +destroy(ns_listenlist_t *list); + +isc_result_t +ns_listenelt_create(isc_mem_t *mctx, in_port_t port, + dns_acl_t *acl, ns_listenelt_t **target) +{ + ns_listenelt_t *elt = NULL; + REQUIRE(target != NULL && *target == NULL); + elt = isc_mem_get(mctx, sizeof(*elt)); + if (elt == NULL) + return (ISC_R_NOMEMORY); + elt->mctx = mctx; + ISC_LINK_INIT(elt, link); + elt->port = port; + elt->acl = acl; + *target = elt; + return (ISC_R_SUCCESS); +} + +void +ns_listenelt_destroy(ns_listenelt_t *elt) { + if (elt->acl != NULL) + dns_acl_detach(&elt->acl); + isc_mem_put(elt->mctx, elt, sizeof(*elt)); +} + +isc_result_t +ns_listenlist_create(isc_mem_t *mctx, ns_listenlist_t **target) { + ns_listenlist_t *list = NULL; + REQUIRE(target != NULL && *target == NULL); + list = isc_mem_get(mctx, sizeof(*list)); + if (list == NULL) + return (ISC_R_NOMEMORY); + list->mctx = mctx; + list->refcount = 1; + ISC_LIST_INIT(list->elts); + *target = list; + return (ISC_R_SUCCESS); +} + +static void +destroy(ns_listenlist_t *list) { + ns_listenelt_t *elt, *next; + for (elt = ISC_LIST_HEAD(list->elts); + elt != NULL; + elt = next) + { + next = ISC_LIST_NEXT(elt, link); + ns_listenelt_destroy(elt); + } + isc_mem_put(list->mctx, list, sizeof(*list)); +} + +void +ns_listenlist_attach(ns_listenlist_t *source, ns_listenlist_t **target) { + INSIST(source->refcount > 0); + source->refcount++; + *target = source; +} + +void +ns_listenlist_detach(ns_listenlist_t **listp) { + ns_listenlist_t *list = *listp; + INSIST(list->refcount > 0); + list->refcount--; + if (list->refcount == 0) + destroy(list); + *listp = NULL; +} + +isc_result_t +ns_listenlist_default(isc_mem_t *mctx, in_port_t port, + isc_boolean_t enabled, ns_listenlist_t **target) +{ + isc_result_t result; + dns_acl_t *acl = NULL; + ns_listenelt_t *elt = NULL; + ns_listenlist_t *list = NULL; + + REQUIRE(target != NULL && *target == NULL); + if (enabled) + result = dns_acl_any(mctx, &acl); + else + result = dns_acl_none(mctx, &acl); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = ns_listenelt_create(mctx, port, acl, &elt); + if (result != ISC_R_SUCCESS) + goto cleanup_acl; + + result = ns_listenlist_create(mctx, &list); + if (result != ISC_R_SUCCESS) + goto cleanup_listenelt; + + ISC_LIST_APPEND(list->elts, elt, link); + + *target = list; + return (ISC_R_SUCCESS); + + cleanup_listenelt: + ns_listenelt_destroy(elt); + cleanup_acl: + dns_acl_detach(&acl); + cleanup: + return (result); +} diff --git a/contrib/bind-9.5.2/bin/named/log.c b/contrib/bind-9.5.2/bin/named/log.c new file mode 100644 index 0000000000..5d994b2d31 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/log.c @@ -0,0 +1,236 @@ +/* + * 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 + * 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: log.c,v 1.46.130.3 2009/01/27 21:17:39 jinmei Exp $ */ + +/*! \file */ + +#include + +#include + +#include + +#include + +#ifndef ISC_FACILITY +#define ISC_FACILITY LOG_DAEMON +#endif + +/*% + * When adding a new category, be sure to add the appropriate + * \#define to and to update the list in + * bin/check/check-tool.c. + */ +static isc_logcategory_t categories[] = { + { "", 0 }, + { "client", 0 }, + { "network", 0 }, + { "update", 0 }, + { "queries", 0 }, + { "unmatched", 0 }, + { "update-security", 0 }, + { "query-errors", 0 }, + { NULL, 0 } +}; + +/*% + * When adding a new module, be sure to add the appropriate + * \#define to . + */ +static isc_logmodule_t modules[] = { + { "main", 0 }, + { "client", 0 }, + { "server", 0 }, + { "query", 0 }, + { "interfacemgr", 0 }, + { "update", 0 }, + { "xfer-in", 0 }, + { "xfer-out", 0 }, + { "notify", 0 }, + { "control", 0 }, + { "lwresd", 0 }, + { NULL, 0 } +}; + +isc_result_t +ns_log_init(isc_boolean_t safe) { + isc_result_t result; + isc_logconfig_t *lcfg = NULL; + + ns_g_categories = categories; + ns_g_modules = modules; + + /* + * Setup a logging context. + */ + result = isc_log_create(ns_g_mctx, &ns_g_lctx, &lcfg); + if (result != ISC_R_SUCCESS) + return (result); + + /* + * named-checktool.c:setup_logging() needs to be kept in sync. + */ + isc_log_registercategories(ns_g_lctx, ns_g_categories); + isc_log_registermodules(ns_g_lctx, ns_g_modules); + isc_log_setcontext(ns_g_lctx); + dns_log_init(ns_g_lctx); + dns_log_setcontext(ns_g_lctx); + cfg_log_init(ns_g_lctx); + + if (safe) + result = ns_log_setsafechannels(lcfg); + else + result = ns_log_setdefaultchannels(lcfg); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = ns_log_setdefaultcategory(lcfg); + if (result != ISC_R_SUCCESS) + goto cleanup; + + return (ISC_R_SUCCESS); + + cleanup: + isc_log_destroy(&ns_g_lctx); + isc_log_setcontext(NULL); + dns_log_setcontext(NULL); + + return (result); +} + +isc_result_t +ns_log_setdefaultchannels(isc_logconfig_t *lcfg) { + isc_result_t result; + isc_logdestination_t destination; + + /* + * By default, the logging library makes "default_debug" log to + * stderr. In BIND, we want to override this and log to named.run + * instead, unless the -g option was given. + */ + if (! ns_g_logstderr) { + destination.file.stream = NULL; + destination.file.name = "named.run"; + destination.file.versions = ISC_LOG_ROLLNEVER; + destination.file.maximum_size = 0; + result = isc_log_createchannel(lcfg, "default_debug", + ISC_LOG_TOFILE, + ISC_LOG_DYNAMIC, + &destination, + ISC_LOG_PRINTTIME| + ISC_LOG_DEBUGONLY); + if (result != ISC_R_SUCCESS) + goto cleanup; + } + +#if ISC_FACILITY != LOG_DAEMON + destination.facility = ISC_FACILITY; + result = isc_log_createchannel(lcfg, "default_syslog", + ISC_LOG_TOSYSLOG, ISC_LOG_INFO, + &destination, 0); + if (result != ISC_R_SUCCESS) + goto cleanup; +#endif + + /* + * Set the initial debug level. + */ + isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel); + + result = ISC_R_SUCCESS; + + cleanup: + return (result); +} + +isc_result_t +ns_log_setsafechannels(isc_logconfig_t *lcfg) { + isc_result_t result; +#if ISC_FACILITY != LOG_DAEMON + isc_logdestination_t destination; +#endif + + if (! ns_g_logstderr) { + result = isc_log_createchannel(lcfg, "default_debug", + ISC_LOG_TONULL, + ISC_LOG_DYNAMIC, + NULL, 0); + if (result != ISC_R_SUCCESS) + goto cleanup; + + /* + * Setting the debug level to zero should get the output + * discarded a bit faster. + */ + isc_log_setdebuglevel(ns_g_lctx, 0); + } else { + isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel); + } + +#if ISC_FACILITY != LOG_DAEMON + destination.facility = ISC_FACILITY; + result = isc_log_createchannel(lcfg, "default_syslog", + ISC_LOG_TOSYSLOG, ISC_LOG_INFO, + &destination, 0); + if (result != ISC_R_SUCCESS) + goto cleanup; +#endif + + result = ISC_R_SUCCESS; + + cleanup: + return (result); +} + +isc_result_t +ns_log_setdefaultcategory(isc_logconfig_t *lcfg) { + isc_result_t result; + + if (! ns_g_logstderr) { + result = isc_log_usechannel(lcfg, "default_syslog", + ISC_LOGCATEGORY_DEFAULT, NULL); + if (result != ISC_R_SUCCESS) + goto cleanup; + } + + result = isc_log_usechannel(lcfg, "default_debug", + ISC_LOGCATEGORY_DEFAULT, NULL); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = ISC_R_SUCCESS; + + cleanup: + return (result); +} + +isc_result_t +ns_log_setunmatchedcategory(isc_logconfig_t *lcfg) { + isc_result_t result; + + result = isc_log_usechannel(lcfg, "null", + NS_LOGCATEGORY_UNMATCHED, NULL); + return (result); +} + +void +ns_log_shutdown(void) { + isc_log_destroy(&ns_g_lctx); + isc_log_setcontext(NULL); + dns_log_setcontext(NULL); +} diff --git a/contrib/bind-9.5.2/bin/named/logconf.c b/contrib/bind-9.5.2/bin/named/logconf.c new file mode 100644 index 0000000000..e32496507e --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/logconf.c @@ -0,0 +1,299 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * 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: logconf.c,v 1.42 2007/06/19 23:46:59 tbox Exp $ */ + +/*! \file */ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#define CHECK(op) \ + do { result = (op); \ + if (result != ISC_R_SUCCESS) goto cleanup; \ + } while (0) + +/*% + * Set up a logging category according to the named.conf data + * in 'ccat' and add it to 'lctx'. + */ +static isc_result_t +category_fromconf(const cfg_obj_t *ccat, isc_logconfig_t *lctx) { + isc_result_t result; + const char *catname; + isc_logcategory_t *category; + isc_logmodule_t *module; + const cfg_obj_t *destinations = NULL; + const cfg_listelt_t *element = NULL; + + catname = cfg_obj_asstring(cfg_tuple_get(ccat, "name")); + category = isc_log_categorybyname(ns_g_lctx, catname); + if (category == NULL) { + cfg_obj_log(ccat, ns_g_lctx, ISC_LOG_ERROR, + "unknown logging category '%s' ignored", + catname); + /* + * Allow further processing by returning success. + */ + return (ISC_R_SUCCESS); + } + + module = NULL; + + destinations = cfg_tuple_get(ccat, "destinations"); + for (element = cfg_list_first(destinations); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *channel = cfg_listelt_value(element); + const char *channelname = cfg_obj_asstring(channel); + + result = isc_log_usechannel(lctx, channelname, category, + module); + if (result != ISC_R_SUCCESS) { + isc_log_write(ns_g_lctx, CFG_LOGCATEGORY_CONFIG, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "logging channel '%s': %s", channelname, + isc_result_totext(result)); + return (result); + } + } + return (ISC_R_SUCCESS); +} + +/*% + * Set up a logging channel according to the named.conf data + * in 'cchan' and add it to 'lctx'. + */ +static isc_result_t +channel_fromconf(const cfg_obj_t *channel, isc_logconfig_t *lctx) { + isc_result_t result; + isc_logdestination_t dest; + unsigned int type; + unsigned int flags = 0; + int level; + const char *channelname; + const cfg_obj_t *fileobj = NULL; + const cfg_obj_t *syslogobj = NULL; + const cfg_obj_t *nullobj = NULL; + const cfg_obj_t *stderrobj = NULL; + const cfg_obj_t *severity = NULL; + int i; + + channelname = cfg_obj_asstring(cfg_map_getname(channel)); + + (void)cfg_map_get(channel, "file", &fileobj); + (void)cfg_map_get(channel, "syslog", &syslogobj); + (void)cfg_map_get(channel, "null", &nullobj); + (void)cfg_map_get(channel, "stderr", &stderrobj); + + i = 0; + if (fileobj != NULL) + i++; + if (syslogobj != NULL) + i++; + if (nullobj != NULL) + i++; + if (stderrobj != NULL) + i++; + + if (i != 1) { + cfg_obj_log(channel, ns_g_lctx, ISC_LOG_ERROR, + "channel '%s': exactly one of file, syslog, " + "null, and stderr must be present", channelname); + return (ISC_R_FAILURE); + } + + type = ISC_LOG_TONULL; + + if (fileobj != NULL) { + const cfg_obj_t *pathobj = cfg_tuple_get(fileobj, "file"); + const cfg_obj_t *sizeobj = cfg_tuple_get(fileobj, "size"); + const cfg_obj_t *versionsobj = + cfg_tuple_get(fileobj, "versions"); + isc_int32_t versions = ISC_LOG_ROLLNEVER; + isc_offset_t size = 0; + + type = ISC_LOG_TOFILE; + + if (versionsobj != NULL && cfg_obj_isuint32(versionsobj)) + versions = cfg_obj_asuint32(versionsobj); + if (versionsobj != NULL && cfg_obj_isstring(versionsobj) && + strcasecmp(cfg_obj_asstring(versionsobj), "unlimited") == 0) + versions = ISC_LOG_ROLLINFINITE; + if (sizeobj != NULL && + cfg_obj_isuint64(sizeobj) && + cfg_obj_asuint64(sizeobj) < ISC_OFFSET_MAXIMUM) + size = (isc_offset_t)cfg_obj_asuint64(sizeobj); + dest.file.stream = NULL; + dest.file.name = cfg_obj_asstring(pathobj); + dest.file.versions = versions; + dest.file.maximum_size = size; + } else if (syslogobj != NULL) { + int facility = LOG_DAEMON; + + type = ISC_LOG_TOSYSLOG; + + if (cfg_obj_isstring(syslogobj)) { + const char *facilitystr = cfg_obj_asstring(syslogobj); + (void)isc_syslog_facilityfromstring(facilitystr, + &facility); + } + dest.facility = facility; + } else if (stderrobj != NULL) { + type = ISC_LOG_TOFILEDESC; + dest.file.stream = stderr; + dest.file.name = NULL; + dest.file.versions = ISC_LOG_ROLLNEVER; + dest.file.maximum_size = 0; + } + + /* + * Munge flags. + */ + { + const cfg_obj_t *printcat = NULL; + const cfg_obj_t *printsev = NULL; + const cfg_obj_t *printtime = NULL; + + (void)cfg_map_get(channel, "print-category", &printcat); + (void)cfg_map_get(channel, "print-severity", &printsev); + (void)cfg_map_get(channel, "print-time", &printtime); + + if (printcat != NULL && cfg_obj_asboolean(printcat)) + flags |= ISC_LOG_PRINTCATEGORY; + if (printtime != NULL && cfg_obj_asboolean(printtime)) + flags |= ISC_LOG_PRINTTIME; + if (printsev != NULL && cfg_obj_asboolean(printsev)) + flags |= ISC_LOG_PRINTLEVEL; + } + + level = ISC_LOG_INFO; + if (cfg_map_get(channel, "severity", &severity) == ISC_R_SUCCESS) { + if (cfg_obj_isstring(severity)) { + const char *str = cfg_obj_asstring(severity); + if (strcasecmp(str, "critical") == 0) + level = ISC_LOG_CRITICAL; + else if (strcasecmp(str, "error") == 0) + level = ISC_LOG_ERROR; + else if (strcasecmp(str, "warning") == 0) + level = ISC_LOG_WARNING; + else if (strcasecmp(str, "notice") == 0) + level = ISC_LOG_NOTICE; + else if (strcasecmp(str, "info") == 0) + level = ISC_LOG_INFO; + else if (strcasecmp(str, "dynamic") == 0) + level = ISC_LOG_DYNAMIC; + } else + /* debug */ + level = cfg_obj_asuint32(severity); + } + + result = isc_log_createchannel(lctx, channelname, + type, level, &dest, flags); + + if (result == ISC_R_SUCCESS && type == ISC_LOG_TOFILE) { + FILE *fp; + + /* + * Test that the file can be opened, since isc_log_open() + * can't effectively report failures when called in + * isc_log_doit(). + */ + result = isc_stdio_open(dest.file.name, "a", &fp); + if (result != ISC_R_SUCCESS) + isc_log_write(ns_g_lctx, CFG_LOGCATEGORY_CONFIG, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "logging channel '%s' file '%s': %s", + channelname, dest.file.name, + isc_result_totext(result)); + else + (void)isc_stdio_close(fp); + + /* + * Allow named to continue by returning success. + */ + result = ISC_R_SUCCESS; + } + + return (result); +} + +isc_result_t +ns_log_configure(isc_logconfig_t *logconf, const cfg_obj_t *logstmt) { + isc_result_t result; + const cfg_obj_t *channels = NULL; + const cfg_obj_t *categories = NULL; + const cfg_listelt_t *element; + isc_boolean_t default_set = ISC_FALSE; + isc_boolean_t unmatched_set = ISC_FALSE; + const cfg_obj_t *catname; + + CHECK(ns_log_setdefaultchannels(logconf)); + + (void)cfg_map_get(logstmt, "channel", &channels); + for (element = cfg_list_first(channels); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *channel = cfg_listelt_value(element); + CHECK(channel_fromconf(channel, logconf)); + } + + (void)cfg_map_get(logstmt, "category", &categories); + for (element = cfg_list_first(categories); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *category = cfg_listelt_value(element); + CHECK(category_fromconf(category, logconf)); + if (!default_set) { + catname = cfg_tuple_get(category, "name"); + if (strcmp(cfg_obj_asstring(catname), "default") == 0) + default_set = ISC_TRUE; + } + if (!unmatched_set) { + catname = cfg_tuple_get(category, "name"); + if (strcmp(cfg_obj_asstring(catname), "unmatched") == 0) + unmatched_set = ISC_TRUE; + } + } + + if (!default_set) + CHECK(ns_log_setdefaultcategory(logconf)); + + if (!unmatched_set) + CHECK(ns_log_setunmatchedcategory(logconf)); + + return (ISC_R_SUCCESS); + + cleanup: + if (logconf != NULL) + isc_logconfig_destroy(&logconf); + return (result); +} diff --git a/contrib/bind-9.5.2/bin/named/lwaddr.c b/contrib/bind-9.5.2/bin/named/lwaddr.c new file mode 100644 index 0000000000..44cfc9211a --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/lwaddr.c @@ -0,0 +1,94 @@ +/* + * 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 + * 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: lwaddr.c,v 1.8.130.2 2008/01/11 23:46:27 tbox Exp $ */ + +/*! \file */ + +#include + +#include + +#include +#include +#include + +#include + +#include + +/*% + * Convert addresses from lwres to isc format. + */ +isc_result_t +lwaddr_netaddr_fromlwresaddr(isc_netaddr_t *na, lwres_addr_t *la) { + if (la->family != LWRES_ADDRTYPE_V4 && la->family != LWRES_ADDRTYPE_V6) + return (ISC_R_FAMILYNOSUPPORT); + + if (la->family == LWRES_ADDRTYPE_V4) { + struct in_addr ina; + memcpy(&ina.s_addr, la->address, 4); + isc_netaddr_fromin(na, &ina); + } else { + struct in6_addr ina6; + memcpy(&ina6.s6_addr, la->address, 16); + isc_netaddr_fromin6(na, &ina6); + } + return (ISC_R_SUCCESS); +} + +isc_result_t +lwaddr_sockaddr_fromlwresaddr(isc_sockaddr_t *sa, lwres_addr_t *la, + in_port_t port) +{ + isc_netaddr_t na; + isc_result_t result; + + result = lwaddr_netaddr_fromlwresaddr(&na, la); + if (result != ISC_R_SUCCESS) + return (result); + isc_sockaddr_fromnetaddr(sa, &na, port); + return (ISC_R_SUCCESS); +} + +/*% + * Convert addresses from isc to lwres format. + */ + +isc_result_t +lwaddr_lwresaddr_fromnetaddr(lwres_addr_t *la, isc_netaddr_t *na) { + if (na->family != AF_INET && na->family != AF_INET6) + return (ISC_R_FAMILYNOSUPPORT); + + if (na->family == AF_INET) { + la->family = LWRES_ADDRTYPE_V4; + la->length = 4; + memcpy(la->address, &na->type.in, 4); + } else { + la->family = LWRES_ADDRTYPE_V6; + la->length = 16; + memcpy(la->address, &na->type.in6, 16); + } + return (ISC_R_SUCCESS); +} + +isc_result_t +lwaddr_lwresaddr_fromsockaddr(lwres_addr_t *la, isc_sockaddr_t *sa) { + isc_netaddr_t na; + isc_netaddr_fromsockaddr(&na, sa); + return (lwaddr_lwresaddr_fromnetaddr(la, &na)); +} diff --git a/contrib/bind-9.5.2/bin/named/lwdclient.c b/contrib/bind-9.5.2/bin/named/lwdclient.c new file mode 100644 index 0000000000..a843134002 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/lwdclient.c @@ -0,0 +1,468 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * 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: lwdclient.c,v 1.22 2007/06/18 23:47:18 tbox Exp $ */ + +/*! \file */ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#define SHUTTINGDOWN(cm) ((cm->flags & NS_LWDCLIENTMGR_FLAGSHUTTINGDOWN) != 0) + +static void +lwdclientmgr_shutdown_callback(isc_task_t *task, isc_event_t *ev); + +void +ns_lwdclient_log(int level, const char *format, ...) { + va_list args; + + va_start(args, format); + isc_log_vwrite(dns_lctx, + DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB, + ISC_LOG_DEBUG(level), format, args); + va_end(args); +} + +isc_result_t +ns_lwdclientmgr_create(ns_lwreslistener_t *listener, unsigned int nclients, + isc_taskmgr_t *taskmgr) +{ + ns_lwresd_t *lwresd = listener->manager; + ns_lwdclientmgr_t *cm; + ns_lwdclient_t *client; + unsigned int i; + isc_result_t result = ISC_R_FAILURE; + + cm = isc_mem_get(lwresd->mctx, sizeof(ns_lwdclientmgr_t)); + if (cm == NULL) + return (ISC_R_NOMEMORY); + + cm->listener = NULL; + ns_lwreslistener_attach(listener, &cm->listener); + cm->mctx = lwresd->mctx; + cm->sock = NULL; + isc_socket_attach(listener->sock, &cm->sock); + cm->view = lwresd->view; + cm->lwctx = NULL; + cm->task = NULL; + cm->flags = 0; + ISC_LINK_INIT(cm, link); + ISC_LIST_INIT(cm->idle); + ISC_LIST_INIT(cm->running); + + if (lwres_context_create(&cm->lwctx, cm->mctx, + ns__lwresd_memalloc, ns__lwresd_memfree, + LWRES_CONTEXT_SERVERMODE) + != ISC_R_SUCCESS) + goto errout; + + for (i = 0; i < nclients; i++) { + client = isc_mem_get(lwresd->mctx, sizeof(ns_lwdclient_t)); + if (client != NULL) { + ns_lwdclient_log(50, "created client %p, manager %p", + client, cm); + ns_lwdclient_initialize(client, cm); + } + } + + /* + * If we could create no clients, clean up and return. + */ + if (ISC_LIST_EMPTY(cm->idle)) + goto errout; + + result = isc_task_create(taskmgr, 0, &cm->task); + if (result != ISC_R_SUCCESS) + goto errout; + isc_task_setname(cm->task, "lwdclient", NULL); + + /* + * This MUST be last, since there is no way to cancel an onshutdown... + */ + result = isc_task_onshutdown(cm->task, lwdclientmgr_shutdown_callback, + cm); + if (result != ISC_R_SUCCESS) + goto errout; + + ns_lwreslistener_linkcm(listener, cm); + + return (ISC_R_SUCCESS); + + errout: + client = ISC_LIST_HEAD(cm->idle); + while (client != NULL) { + ISC_LIST_UNLINK(cm->idle, client, link); + isc_mem_put(lwresd->mctx, client, sizeof(*client)); + client = ISC_LIST_HEAD(cm->idle); + } + + if (cm->task != NULL) + isc_task_detach(&cm->task); + + if (cm->lwctx != NULL) + lwres_context_destroy(&cm->lwctx); + + isc_mem_put(lwresd->mctx, cm, sizeof(*cm)); + return (result); +} + +static void +lwdclientmgr_destroy(ns_lwdclientmgr_t *cm) { + ns_lwdclient_t *client; + ns_lwreslistener_t *listener; + + if (!SHUTTINGDOWN(cm)) + return; + + /* + * run through the idle list and free the clients there. Idle + * clients do not have a recv running nor do they have any finds + * or similar running. + */ + client = ISC_LIST_HEAD(cm->idle); + while (client != NULL) { + ns_lwdclient_log(50, "destroying client %p, manager %p", + client, cm); + ISC_LIST_UNLINK(cm->idle, client, link); + isc_mem_put(cm->mctx, client, sizeof(*client)); + client = ISC_LIST_HEAD(cm->idle); + } + + if (!ISC_LIST_EMPTY(cm->running)) + return; + + lwres_context_destroy(&cm->lwctx); + cm->view = NULL; + isc_socket_detach(&cm->sock); + isc_task_detach(&cm->task); + + listener = cm->listener; + ns_lwreslistener_unlinkcm(listener, cm); + ns_lwdclient_log(50, "destroying manager %p", cm); + isc_mem_put(cm->mctx, cm, sizeof(*cm)); + ns_lwreslistener_detach(&listener); +} + +static void +process_request(ns_lwdclient_t *client) { + lwres_buffer_t b; + isc_result_t result; + + lwres_buffer_init(&b, client->buffer, client->recvlength); + lwres_buffer_add(&b, client->recvlength); + + result = lwres_lwpacket_parseheader(&b, &client->pkt); + if (result != ISC_R_SUCCESS) { + ns_lwdclient_log(50, "invalid packet header received"); + goto restart; + } + + ns_lwdclient_log(50, "opcode %08x", client->pkt.opcode); + + switch (client->pkt.opcode) { + case LWRES_OPCODE_GETADDRSBYNAME: + ns_lwdclient_processgabn(client, &b); + return; + case LWRES_OPCODE_GETNAMEBYADDR: + ns_lwdclient_processgnba(client, &b); + return; + case LWRES_OPCODE_GETRDATABYNAME: + ns_lwdclient_processgrbn(client, &b); + return; + case LWRES_OPCODE_NOOP: + ns_lwdclient_processnoop(client, &b); + return; + default: + ns_lwdclient_log(50, "unknown opcode %08x", client->pkt.opcode); + goto restart; + } + + /* + * Drop the packet. + */ + restart: + ns_lwdclient_log(50, "restarting client %p...", client); + ns_lwdclient_stateidle(client); +} + +void +ns_lwdclient_recv(isc_task_t *task, isc_event_t *ev) { + isc_result_t result; + ns_lwdclient_t *client = ev->ev_arg; + ns_lwdclientmgr_t *cm = client->clientmgr; + isc_socketevent_t *dev = (isc_socketevent_t *)ev; + + INSIST(dev->region.base == client->buffer); + INSIST(NS_LWDCLIENT_ISRECV(client)); + + NS_LWDCLIENT_SETRECVDONE(client); + + INSIST((cm->flags & NS_LWDCLIENTMGR_FLAGRECVPENDING) != 0); + cm->flags &= ~NS_LWDCLIENTMGR_FLAGRECVPENDING; + + ns_lwdclient_log(50, + "event received: task %p, length %u, result %u (%s)", + task, dev->n, dev->result, + isc_result_totext(dev->result)); + + if (dev->result != ISC_R_SUCCESS) { + isc_event_free(&ev); + dev = NULL; + + /* + * Go idle. + */ + ns_lwdclient_stateidle(client); + + return; + } + + client->recvlength = dev->n; + client->address = dev->address; + if ((dev->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0) { + client->pktinfo = dev->pktinfo; + client->pktinfo_valid = ISC_TRUE; + } else + client->pktinfo_valid = ISC_FALSE; + isc_event_free(&ev); + dev = NULL; + + result = ns_lwdclient_startrecv(cm); + if (result != ISC_R_SUCCESS) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_LWRESD, ISC_LOG_ERROR, + "could not start lwres " + "client handler: %s", + isc_result_totext(result)); + + process_request(client); +} + +/* + * This function will start a new recv() on a socket for this client manager. + */ +isc_result_t +ns_lwdclient_startrecv(ns_lwdclientmgr_t *cm) { + ns_lwdclient_t *client; + isc_result_t result; + isc_region_t r; + + if (SHUTTINGDOWN(cm)) { + lwdclientmgr_destroy(cm); + return (ISC_R_SUCCESS); + } + + /* + * If a recv is already running, don't bother. + */ + if ((cm->flags & NS_LWDCLIENTMGR_FLAGRECVPENDING) != 0) + return (ISC_R_SUCCESS); + + /* + * If we have no idle slots, just return success. + */ + client = ISC_LIST_HEAD(cm->idle); + if (client == NULL) + return (ISC_R_SUCCESS); + INSIST(NS_LWDCLIENT_ISIDLE(client)); + + /* + * Issue the recv. If it fails, return that it did. + */ + r.base = client->buffer; + r.length = LWRES_RECVLENGTH; + result = isc_socket_recv(cm->sock, &r, 0, cm->task, ns_lwdclient_recv, + client); + if (result != ISC_R_SUCCESS) + return (result); + + /* + * Set the flag to say we've issued a recv() call. + */ + cm->flags |= NS_LWDCLIENTMGR_FLAGRECVPENDING; + + /* + * Remove the client from the idle list, and put it on the running + * list. + */ + NS_LWDCLIENT_SETRECV(client); + ISC_LIST_UNLINK(cm->idle, client, link); + ISC_LIST_APPEND(cm->running, client, link); + + return (ISC_R_SUCCESS); +} + +static void +lwdclientmgr_shutdown_callback(isc_task_t *task, isc_event_t *ev) { + ns_lwdclientmgr_t *cm = ev->ev_arg; + ns_lwdclient_t *client; + + REQUIRE(!SHUTTINGDOWN(cm)); + + ns_lwdclient_log(50, "got shutdown event, task %p, lwdclientmgr %p", + task, cm); + + /* + * run through the idle list and free the clients there. Idle + * clients do not have a recv running nor do they have any finds + * or similar running. + */ + client = ISC_LIST_HEAD(cm->idle); + while (client != NULL) { + ns_lwdclient_log(50, "destroying client %p, manager %p", + client, cm); + ISC_LIST_UNLINK(cm->idle, client, link); + isc_mem_put(cm->mctx, client, sizeof(*client)); + client = ISC_LIST_HEAD(cm->idle); + } + + /* + * Cancel any pending I/O. + */ + isc_socket_cancel(cm->sock, task, ISC_SOCKCANCEL_ALL); + + /* + * Run through the running client list and kill off any finds + * in progress. + */ + client = ISC_LIST_HEAD(cm->running); + while (client != NULL) { + if (client->find != client->v4find + && client->find != client->v6find) + dns_adb_cancelfind(client->find); + if (client->v4find != NULL) + dns_adb_cancelfind(client->v4find); + if (client->v6find != NULL) + dns_adb_cancelfind(client->v6find); + client = ISC_LIST_NEXT(client, link); + } + + cm->flags |= NS_LWDCLIENTMGR_FLAGSHUTTINGDOWN; + + isc_event_free(&ev); +} + +/* + * Do all the crap needed to move a client from the run queue to the idle + * queue. + */ +void +ns_lwdclient_stateidle(ns_lwdclient_t *client) { + ns_lwdclientmgr_t *cm; + isc_result_t result; + + cm = client->clientmgr; + + INSIST(client->sendbuf == NULL); + INSIST(client->sendlength == 0); + INSIST(client->arg == NULL); + INSIST(client->v4find == NULL); + INSIST(client->v6find == NULL); + + ISC_LIST_UNLINK(cm->running, client, link); + ISC_LIST_PREPEND(cm->idle, client, link); + + NS_LWDCLIENT_SETIDLE(client); + + result = ns_lwdclient_startrecv(cm); + if (result != ISC_R_SUCCESS) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_LWRESD, ISC_LOG_ERROR, + "could not start lwres " + "client handler: %s", + isc_result_totext(result)); +} + +void +ns_lwdclient_send(isc_task_t *task, isc_event_t *ev) { + ns_lwdclient_t *client = ev->ev_arg; + ns_lwdclientmgr_t *cm = client->clientmgr; + isc_socketevent_t *dev = (isc_socketevent_t *)ev; + + UNUSED(task); + UNUSED(dev); + + INSIST(NS_LWDCLIENT_ISSEND(client)); + INSIST(client->sendbuf == dev->region.base); + + ns_lwdclient_log(50, "task %p for client %p got send-done event", + task, client); + + if (client->sendbuf != client->buffer) + lwres_context_freemem(cm->lwctx, client->sendbuf, + client->sendlength); + client->sendbuf = NULL; + client->sendlength = 0; + + ns_lwdclient_stateidle(client); + + isc_event_free(&ev); +} + +isc_result_t +ns_lwdclient_sendreply(ns_lwdclient_t *client, isc_region_t *r) { + struct in6_pktinfo *pktinfo; + ns_lwdclientmgr_t *cm = client->clientmgr; + + if (client->pktinfo_valid) + pktinfo = &client->pktinfo; + else + pktinfo = NULL; + return (isc_socket_sendto(cm->sock, r, cm->task, ns_lwdclient_send, + client, &client->address, pktinfo)); +} + +void +ns_lwdclient_initialize(ns_lwdclient_t *client, ns_lwdclientmgr_t *cmgr) { + client->clientmgr = cmgr; + ISC_LINK_INIT(client, link); + NS_LWDCLIENT_SETIDLE(client); + client->arg = NULL; + + client->recvlength = 0; + + client->sendbuf = NULL; + client->sendlength = 0; + + client->find = NULL; + client->v4find = NULL; + client->v6find = NULL; + client->find_wanted = 0; + + client->options = 0; + client->byaddr = NULL; + + client->lookup = NULL; + + client->pktinfo_valid = ISC_FALSE; + + ISC_LIST_APPEND(cmgr->idle, client, link); +} diff --git a/contrib/bind-9.5.2/bin/named/lwderror.c b/contrib/bind-9.5.2/bin/named/lwderror.c new file mode 100644 index 0000000000..33f247a458 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/lwderror.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * 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: lwderror.c,v 1.12 2007/06/19 23:46:59 tbox Exp $ */ + +/*! \file */ + +#include + +#include +#include + +#include +#include + +/*% + * Generate an error packet for the client, schedule a send, and put us in + * the SEND state. + * + * The client->pkt structure will be modified to form an error return. + * The receiver needs to verify that it is in fact an error, and do the + * right thing with it. The opcode will be unchanged. The result needs + * to be set before calling this function. + * + * The only change this code makes is to set the receive buffer size to the + * size we use, set the reply bit, and recompute any security information. + */ +void +ns_lwdclient_errorpktsend(ns_lwdclient_t *client, isc_uint32_t _result) { + isc_result_t result; + int lwres; + isc_region_t r; + lwres_buffer_t b; + + REQUIRE(NS_LWDCLIENT_ISRUNNING(client)); + + /* + * Since we are only sending the packet header, we can safely toss + * the receive buffer. This means we won't need to allocate space + * for sending an error reply. This is a Good Thing. + */ + client->pkt.length = LWRES_LWPACKET_LENGTH; + client->pkt.pktflags |= LWRES_LWPACKETFLAG_RESPONSE; + client->pkt.recvlength = LWRES_RECVLENGTH; + client->pkt.authtype = 0; /* XXXMLG */ + client->pkt.authlength = 0; + client->pkt.result = _result; + + lwres_buffer_init(&b, client->buffer, LWRES_RECVLENGTH); + lwres = lwres_lwpacket_renderheader(&b, &client->pkt); + if (lwres != LWRES_R_SUCCESS) { + ns_lwdclient_stateidle(client); + return; + } + + r.base = client->buffer; + r.length = b.used; + client->sendbuf = client->buffer; + result = ns_lwdclient_sendreply(client, &r); + if (result != ISC_R_SUCCESS) { + ns_lwdclient_stateidle(client); + return; + } + + NS_LWDCLIENT_SETSEND(client); +} diff --git a/contrib/bind-9.5.2/bin/named/lwdgabn.c b/contrib/bind-9.5.2/bin/named/lwdgabn.c new file mode 100644 index 0000000000..dec1e1a571 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/lwdgabn.c @@ -0,0 +1,657 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * 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: lwdgabn.c,v 1.22 2007/06/19 23:46:59 tbox Exp $ */ + +/*! \file */ + +#include + +#include + +#include +#include +#include +#include /* Required for HP/UX (and others?) */ +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define NEED_V4(c) ((((c)->find_wanted & LWRES_ADDRTYPE_V4) != 0) \ + && ((c)->v4find == NULL)) +#define NEED_V6(c) ((((c)->find_wanted & LWRES_ADDRTYPE_V6) != 0) \ + && ((c)->v6find == NULL)) + +static isc_result_t start_find(ns_lwdclient_t *); +static void restart_find(ns_lwdclient_t *); +static void init_gabn(ns_lwdclient_t *); + +/*% + * Destroy any finds. This can be used to "start over from scratch" and + * should only be called when events are _not_ being generated by the finds. + */ +static void +cleanup_gabn(ns_lwdclient_t *client) { + ns_lwdclient_log(50, "cleaning up client %p", client); + + if (client->v6find != NULL) { + if (client->v6find == client->v4find) + client->v6find = NULL; + else + dns_adb_destroyfind(&client->v6find); + } + if (client->v4find != NULL) + dns_adb_destroyfind(&client->v4find); +} + +static void +setup_addresses(ns_lwdclient_t *client, dns_adbfind_t *find, unsigned int at) { + dns_adbaddrinfo_t *ai; + lwres_addr_t *addr; + int af; + const struct sockaddr *sa; + isc_result_t result; + + if (at == DNS_ADBFIND_INET) + af = AF_INET; + else + af = AF_INET6; + + ai = ISC_LIST_HEAD(find->list); + while (ai != NULL && client->gabn.naddrs < LWRES_MAX_ADDRS) { + sa = &ai->sockaddr.type.sa; + if (sa->sa_family != af) + goto next; + + addr = &client->addrs[client->gabn.naddrs]; + + result = lwaddr_lwresaddr_fromsockaddr(addr, &ai->sockaddr); + if (result != ISC_R_SUCCESS) + goto next; + + ns_lwdclient_log(50, "adding address %p, family %d, length %d", + addr->address, addr->family, addr->length); + + client->gabn.naddrs++; + REQUIRE(!LWRES_LINK_LINKED(addr, link)); + LWRES_LIST_APPEND(client->gabn.addrs, addr, link); + + next: + ai = ISC_LIST_NEXT(ai, publink); + } +} + +typedef struct { + isc_netaddr_t address; + int rank; +} rankedaddress; + +static int +addr_compare(const void *av, const void *bv) { + const rankedaddress *a = (const rankedaddress *) av; + const rankedaddress *b = (const rankedaddress *) bv; + return (a->rank - b->rank); +} + +static void +sort_addresses(ns_lwdclient_t *client) { + unsigned int naddrs; + rankedaddress *addrs; + isc_netaddr_t remote; + dns_addressorderfunc_t order; + const void *arg; + ns_lwresd_t *lwresd = client->clientmgr->listener->manager; + unsigned int i; + isc_result_t result; + + naddrs = client->gabn.naddrs; + + if (naddrs <= 1 || lwresd->view->sortlist == NULL) + return; + + addrs = isc_mem_get(lwresd->mctx, sizeof(rankedaddress) * naddrs); + if (addrs == NULL) + return; + + isc_netaddr_fromsockaddr(&remote, &client->address); + ns_sortlist_byaddrsetup(lwresd->view->sortlist, + &remote, &order, &arg); + if (order == NULL) { + isc_mem_put(lwresd->mctx, addrs, + sizeof(rankedaddress) * naddrs); + return; + } + for (i = 0; i < naddrs; i++) { + result = lwaddr_netaddr_fromlwresaddr(&addrs[i].address, + &client->addrs[i]); + INSIST(result == ISC_R_SUCCESS); + addrs[i].rank = (*order)(&addrs[i].address, arg); + } + qsort(addrs, naddrs, sizeof(rankedaddress), addr_compare); + for (i = 0; i < naddrs; i++) { + result = lwaddr_lwresaddr_fromnetaddr(&client->addrs[i], + &addrs[i].address); + INSIST(result == ISC_R_SUCCESS); + } + + isc_mem_put(lwresd->mctx, addrs, sizeof(rankedaddress) * naddrs); +} + +static void +generate_reply(ns_lwdclient_t *client) { + isc_result_t result; + int lwres; + isc_region_t r; + lwres_buffer_t lwb; + ns_lwdclientmgr_t *cm; + + cm = client->clientmgr; + lwb.base = NULL; + + ns_lwdclient_log(50, "generating gabn reply for client %p", client); + + /* + * We must make certain the client->find is not still active. + * If it is either the v4 or v6 answer, just set it to NULL and + * let the cleanup code destroy it. Otherwise, destroy it now. + */ + if (client->find == client->v4find || client->find == client->v6find) + client->find = NULL; + else + if (client->find != NULL) + dns_adb_destroyfind(&client->find); + + /* + * perhaps there are some here? + */ + if (NEED_V6(client) && client->v4find != NULL) + client->v6find = client->v4find; + + /* + * Run through the finds we have and wire them up to the gabn + * structure. + */ + LWRES_LIST_INIT(client->gabn.addrs); + if (client->v4find != NULL) + setup_addresses(client, client->v4find, DNS_ADBFIND_INET); + if (client->v6find != NULL) + setup_addresses(client, client->v6find, DNS_ADBFIND_INET6); + + /* + * If there are no addresses, try the next element in the search + * path, if there are any more. Otherwise, fall through into + * the error handling code below. + */ + if (client->gabn.naddrs == 0) { + do { + result = ns_lwsearchctx_next(&client->searchctx); + if (result == ISC_R_SUCCESS) { + cleanup_gabn(client); + result = start_find(client); + if (result == ISC_R_SUCCESS) + return; + } + } while (result == ISC_R_SUCCESS); + } + + /* + * Render the packet. + */ + client->pkt.recvlength = LWRES_RECVLENGTH; + client->pkt.authtype = 0; /* XXXMLG */ + client->pkt.authlength = 0; + + /* + * If there are no addresses, return failure. + */ + if (client->gabn.naddrs != 0) + client->pkt.result = LWRES_R_SUCCESS; + else + client->pkt.result = LWRES_R_NOTFOUND; + + sort_addresses(client); + + lwres = lwres_gabnresponse_render(cm->lwctx, &client->gabn, + &client->pkt, &lwb); + if (lwres != LWRES_R_SUCCESS) + goto out; + + r.base = lwb.base; + r.length = lwb.used; + client->sendbuf = r.base; + client->sendlength = r.length; + result = ns_lwdclient_sendreply(client, &r); + if (result != ISC_R_SUCCESS) + goto out; + + NS_LWDCLIENT_SETSEND(client); + + /* + * All done! + */ + cleanup_gabn(client); + + return; + + out: + cleanup_gabn(client); + + if (lwb.base != NULL) + lwres_context_freemem(client->clientmgr->lwctx, + lwb.base, lwb.length); + + ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); +} + +/* + * Take the current real name, move it to an alias slot (if any are + * open) then put this new name in as the real name for the target. + * + * Return success if it can be rendered, otherwise failure. Note that + * not having enough alias slots open is NOT a failure. + */ +static isc_result_t +add_alias(ns_lwdclient_t *client) { + isc_buffer_t b; + isc_result_t result; + isc_uint16_t naliases; + + b = client->recv_buffer; + + /* + * Render the new name to the buffer. + */ + result = dns_name_totext(dns_fixedname_name(&client->target_name), + ISC_TRUE, &client->recv_buffer); + if (result != ISC_R_SUCCESS) + return (result); + + /* + * Are there any open slots? + */ + naliases = client->gabn.naliases; + if (naliases < LWRES_MAX_ALIASES) { + client->gabn.aliases[naliases] = client->gabn.realname; + client->gabn.aliaslen[naliases] = client->gabn.realnamelen; + client->gabn.naliases++; + } + + /* + * Save this name away as the current real name. + */ + client->gabn.realname = (char *)(b.base) + b.used; + client->gabn.realnamelen = client->recv_buffer.used - b.used; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +store_realname(ns_lwdclient_t *client) { + isc_buffer_t b; + isc_result_t result; + dns_name_t *tname; + + b = client->recv_buffer; + + tname = dns_fixedname_name(&client->target_name); + result = ns_lwsearchctx_current(&client->searchctx, tname); + if (result != ISC_R_SUCCESS) + return (result); + + /* + * Render the new name to the buffer. + */ + result = dns_name_totext(tname, ISC_TRUE, &client->recv_buffer); + if (result != ISC_R_SUCCESS) + return (result); + + /* + * Save this name away as the current real name. + */ + client->gabn.realname = (char *) b.base + b.used; + client->gabn.realnamelen = client->recv_buffer.used - b.used; + + return (ISC_R_SUCCESS); +} + +static void +process_gabn_finddone(isc_task_t *task, isc_event_t *ev) { + ns_lwdclient_t *client = ev->ev_arg; + isc_eventtype_t evtype; + isc_boolean_t claimed; + + ns_lwdclient_log(50, "find done for task %p, client %p", task, client); + + evtype = ev->ev_type; + isc_event_free(&ev); + + /* + * No more info to be had? If so, we have all the good stuff + * right now, so we can render things. + */ + claimed = ISC_FALSE; + if (evtype == DNS_EVENT_ADBNOMOREADDRESSES) { + if (NEED_V4(client)) { + client->v4find = client->find; + claimed = ISC_TRUE; + } + if (NEED_V6(client)) { + client->v6find = client->find; + claimed = ISC_TRUE; + } + if (client->find != NULL) { + if (claimed) + client->find = NULL; + else + dns_adb_destroyfind(&client->find); + + } + generate_reply(client); + return; + } + + /* + * We probably don't need this find anymore. We're either going to + * reissue it, or an error occurred. Either way, we're done with + * it. + */ + if ((client->find != client->v4find) + && (client->find != client->v6find)) { + dns_adb_destroyfind(&client->find); + } else { + client->find = NULL; + } + + /* + * We have some new information we can gather. Run off and fetch + * it. + */ + if (evtype == DNS_EVENT_ADBMOREADDRESSES) { + restart_find(client); + return; + } + + /* + * An error or other strangeness happened. Drop this query. + */ + cleanup_gabn(client); + ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); +} + +static void +restart_find(ns_lwdclient_t *client) { + unsigned int options; + isc_result_t result; + isc_boolean_t claimed; + + ns_lwdclient_log(50, "starting find for client %p", client); + + /* + * Issue a find for the name contained in the request. We won't + * set the bit that says "anything is good enough" -- we want it + * all. + */ + options = 0; + options |= DNS_ADBFIND_WANTEVENT; + options |= DNS_ADBFIND_RETURNLAME; + + /* + * Set the bits up here to mark that we want this address family + * and that we do not currently have a find pending. We will + * set that bit again below if it turns out we will get an event. + */ + if (NEED_V4(client)) + options |= DNS_ADBFIND_INET; + if (NEED_V6(client)) + options |= DNS_ADBFIND_INET6; + + find_again: + INSIST(client->find == NULL); + result = dns_adb_createfind(client->clientmgr->view->adb, + client->clientmgr->task, + process_gabn_finddone, client, + dns_fixedname_name(&client->target_name), + dns_rootname, 0, options, 0, + dns_fixedname_name(&client->target_name), + client->clientmgr->view->dstport, + &client->find); + + /* + * Did we get an alias? If so, save it and re-issue the query. + */ + if (result == DNS_R_ALIAS) { + ns_lwdclient_log(50, "found alias, restarting query"); + dns_adb_destroyfind(&client->find); + cleanup_gabn(client); + result = add_alias(client); + if (result != ISC_R_SUCCESS) { + ns_lwdclient_log(50, + "out of buffer space adding alias"); + ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); + return; + } + goto find_again; + } + + ns_lwdclient_log(50, "find returned %d (%s)", result, + isc_result_totext(result)); + + /* + * Did we get an error? + */ + if (result != ISC_R_SUCCESS) { + if (client->find != NULL) + dns_adb_destroyfind(&client->find); + cleanup_gabn(client); + ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); + return; + } + + claimed = ISC_FALSE; + + /* + * Did we get our answer to V4 addresses? + */ + if (NEED_V4(client) + && ((client->find->query_pending & DNS_ADBFIND_INET) == 0)) { + ns_lwdclient_log(50, "client %p ipv4 satisfied by find %p", + client, client->find); + claimed = ISC_TRUE; + client->v4find = client->find; + } + + /* + * Did we get our answer to V6 addresses? + */ + if (NEED_V6(client) + && ((client->find->query_pending & DNS_ADBFIND_INET6) == 0)) { + ns_lwdclient_log(50, "client %p ipv6 satisfied by find %p", + client, client->find); + claimed = ISC_TRUE; + client->v6find = client->find; + } + + /* + * If we're going to get an event, set our internal pending flag + * and return. When we get an event back we'll do the right + * thing, basically by calling this function again, perhaps with a + * new target name. + * + * If we have both v4 and v6, and we are still getting an event, + * we have a programming error, so die hard. + */ + if ((client->find->options & DNS_ADBFIND_WANTEVENT) != 0) { + ns_lwdclient_log(50, "event will be sent"); + INSIST(client->v4find == NULL || client->v6find == NULL); + return; + } + ns_lwdclient_log(50, "no event will be sent"); + if (claimed) + client->find = NULL; + else + dns_adb_destroyfind(&client->find); + + /* + * We seem to have everything we asked for, or at least we are + * able to respond with things we've learned. + */ + + generate_reply(client); +} + +static isc_result_t +start_find(ns_lwdclient_t *client) { + isc_result_t result; + + /* + * Initialize the real name and alias arrays in the reply we're + * going to build up. + */ + init_gabn(client); + + result = store_realname(client); + if (result != ISC_R_SUCCESS) + return (result); + restart_find(client); + return (ISC_R_SUCCESS); + +} + +static void +init_gabn(ns_lwdclient_t *client) { + int i; + + /* + * Initialize the real name and alias arrays in the reply we're + * going to build up. + */ + for (i = 0; i < LWRES_MAX_ALIASES; i++) { + client->aliases[i] = NULL; + client->aliaslen[i] = 0; + } + for (i = 0; i < LWRES_MAX_ADDRS; i++) { + client->addrs[i].family = 0; + client->addrs[i].length = 0; + memset(client->addrs[i].address, 0, LWRES_ADDR_MAXLEN); + LWRES_LINK_INIT(&client->addrs[i], link); + } + + client->gabn.naliases = 0; + client->gabn.naddrs = 0; + client->gabn.realname = NULL; + client->gabn.aliases = client->aliases; + client->gabn.realnamelen = 0; + client->gabn.aliaslen = client->aliaslen; + LWRES_LIST_INIT(client->gabn.addrs); + client->gabn.base = NULL; + client->gabn.baselen = 0; + + /* + * Set up the internal buffer to point to the receive region. + */ + isc_buffer_init(&client->recv_buffer, client->buffer, LWRES_RECVLENGTH); +} + +/* + * When we are called, we can be assured that: + * + * client->sockaddr contains the address we need to reply to, + * + * client->pkt contains the packet header data, + * + * the packet "checks out" overall -- any MD5 hashes or crypto + * bits have been verified, + * + * "b" points to the remaining data after the packet header + * was parsed off. + * + * We are in a the RECVDONE state. + * + * From this state we will enter the SEND state if we happen to have + * everything we need or we need to return an error packet, or to the + * FINDWAIT state if we need to look things up. + */ +void +ns_lwdclient_processgabn(ns_lwdclient_t *client, lwres_buffer_t *b) { + isc_result_t result; + lwres_gabnrequest_t *req; + ns_lwdclientmgr_t *cm; + isc_buffer_t namebuf; + + REQUIRE(NS_LWDCLIENT_ISRECVDONE(client)); + + cm = client->clientmgr; + req = NULL; + + result = lwres_gabnrequest_parse(client->clientmgr->lwctx, + b, &client->pkt, &req); + if (result != LWRES_R_SUCCESS) + goto out; + if (req->name == NULL) + goto out; + + isc_buffer_init(&namebuf, req->name, req->namelen); + isc_buffer_add(&namebuf, req->namelen); + + dns_fixedname_init(&client->target_name); + dns_fixedname_init(&client->query_name); + result = dns_name_fromtext(dns_fixedname_name(&client->query_name), + &namebuf, NULL, ISC_FALSE, NULL); + if (result != ISC_R_SUCCESS) + goto out; + ns_lwsearchctx_init(&client->searchctx, + cm->listener->manager->search, + dns_fixedname_name(&client->query_name), + cm->listener->manager->ndots); + ns_lwsearchctx_first(&client->searchctx); + + client->find_wanted = req->addrtypes; + ns_lwdclient_log(50, "client %p looking for addrtypes %08x", + client, client->find_wanted); + + /* + * We no longer need to keep this around. + */ + lwres_gabnrequest_free(client->clientmgr->lwctx, &req); + + /* + * Start the find. + */ + result = start_find(client); + if (result != ISC_R_SUCCESS) + goto out; + + return; + + /* + * We're screwed. Return an error packet to our caller. + */ + out: + if (req != NULL) + lwres_gabnrequest_free(client->clientmgr->lwctx, &req); + + ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); +} diff --git a/contrib/bind-9.5.2/bin/named/lwdgnba.c b/contrib/bind-9.5.2/bin/named/lwdgnba.c new file mode 100644 index 0000000000..2309329df1 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/lwdgnba.c @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2002 Internet Software Consortium. + * + * 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: lwdgnba.c,v 1.20.130.2 2008/01/14 23:46:28 tbox Exp $ */ + +/*! \file */ + +#include + +#include +#include /* Required for HP/UX (and others?) */ +#include + +#include +#include +#include + +#include +#include + +static void start_byaddr(ns_lwdclient_t *); + +static void +byaddr_done(isc_task_t *task, isc_event_t *event) { + ns_lwdclient_t *client; + ns_lwdclientmgr_t *cm; + dns_byaddrevent_t *bevent; + int lwres; + lwres_buffer_t lwb; + dns_name_t *name; + isc_result_t result; + lwres_result_t lwresult; + isc_region_t r; + isc_buffer_t b; + lwres_gnbaresponse_t *gnba; + isc_uint16_t naliases; + + UNUSED(task); + + lwb.base = NULL; + client = event->ev_arg; + cm = client->clientmgr; + INSIST(client->byaddr == (dns_byaddr_t *)event->ev_sender); + + bevent = (dns_byaddrevent_t *)event; + gnba = &client->gnba; + + ns_lwdclient_log(50, "byaddr event result = %s", + isc_result_totext(bevent->result)); + + result = bevent->result; + if (result != ISC_R_SUCCESS) { + dns_byaddr_destroy(&client->byaddr); + isc_event_free(&event); + bevent = NULL; + + if (client->na.family != AF_INET6 || + (client->options & DNS_BYADDROPT_IPV6INT) != 0) { + if (result == DNS_R_NCACHENXDOMAIN || + result == DNS_R_NCACHENXRRSET || + result == DNS_R_NXDOMAIN || + result == DNS_R_NXRRSET) + lwresult = LWRES_R_NOTFOUND; + else + lwresult = LWRES_R_FAILURE; + ns_lwdclient_errorpktsend(client, lwresult); + return; + } + + /* + * Fall back to ip6.int reverse if the default ip6.arpa + * fails. + */ + client->options |= DNS_BYADDROPT_IPV6INT; + + start_byaddr(client); + return; + } + + for (name = ISC_LIST_HEAD(bevent->names); + name != NULL; + name = ISC_LIST_NEXT(name, link)) + { + b = client->recv_buffer; + + result = dns_name_totext(name, ISC_TRUE, &client->recv_buffer); + if (result != ISC_R_SUCCESS) + goto out; + ns_lwdclient_log(50, "found name '%.*s'", + (int)(client->recv_buffer.used - b.used), + (char *)(b.base) + b.used); + if (gnba->realname == NULL) { + gnba->realname = (char *)(b.base) + b.used; + gnba->realnamelen = client->recv_buffer.used - b.used; + } else { + naliases = gnba->naliases; + if (naliases >= LWRES_MAX_ALIASES) + break; + gnba->aliases[naliases] = (char *)(b.base) + b.used; + gnba->aliaslen[naliases] = + client->recv_buffer.used - b.used; + gnba->naliases++; + } + } + + dns_byaddr_destroy(&client->byaddr); + isc_event_free(&event); + + /* + * Render the packet. + */ + client->pkt.recvlength = LWRES_RECVLENGTH; + client->pkt.authtype = 0; /* XXXMLG */ + client->pkt.authlength = 0; + client->pkt.result = LWRES_R_SUCCESS; + + lwres = lwres_gnbaresponse_render(cm->lwctx, + gnba, &client->pkt, &lwb); + if (lwres != LWRES_R_SUCCESS) + goto out; + + r.base = lwb.base; + r.length = lwb.used; + client->sendbuf = r.base; + client->sendlength = r.length; + result = ns_lwdclient_sendreply(client, &r); + if (result != ISC_R_SUCCESS) + goto out; + + NS_LWDCLIENT_SETSEND(client); + + return; + + out: + if (client->byaddr != NULL) + dns_byaddr_destroy(&client->byaddr); + if (lwb.base != NULL) + lwres_context_freemem(cm->lwctx, + lwb.base, lwb.length); + + if (event != NULL) + isc_event_free(&event); +} + +static void +start_byaddr(ns_lwdclient_t *client) { + isc_result_t result; + ns_lwdclientmgr_t *cm; + + cm = client->clientmgr; + + INSIST(client->byaddr == NULL); + + result = dns_byaddr_create(cm->mctx, &client->na, cm->view, + client->options, cm->task, byaddr_done, + client, &client->byaddr); + if (result != ISC_R_SUCCESS) { + ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); + return; + } +} + +static void +init_gnba(ns_lwdclient_t *client) { + int i; + + /* + * Initialize the real name and alias arrays in the reply we're + * going to build up. + */ + for (i = 0; i < LWRES_MAX_ALIASES; i++) { + client->aliases[i] = NULL; + client->aliaslen[i] = 0; + } + for (i = 0; i < LWRES_MAX_ADDRS; i++) { + client->addrs[i].family = 0; + client->addrs[i].length = 0; + memset(client->addrs[i].address, 0, LWRES_ADDR_MAXLEN); + LWRES_LINK_INIT(&client->addrs[i], link); + } + + client->gnba.naliases = 0; + client->gnba.realname = NULL; + client->gnba.aliases = client->aliases; + client->gnba.realnamelen = 0; + client->gnba.aliaslen = client->aliaslen; + client->gnba.base = NULL; + client->gnba.baselen = 0; + isc_buffer_init(&client->recv_buffer, client->buffer, LWRES_RECVLENGTH); +} + +void +ns_lwdclient_processgnba(ns_lwdclient_t *client, lwres_buffer_t *b) { + lwres_gnbarequest_t *req; + isc_result_t result; + isc_sockaddr_t sa; + ns_lwdclientmgr_t *cm; + + REQUIRE(NS_LWDCLIENT_ISRECVDONE(client)); + INSIST(client->byaddr == NULL); + + cm = client->clientmgr; + req = NULL; + + result = lwres_gnbarequest_parse(cm->lwctx, + b, &client->pkt, &req); + if (result != LWRES_R_SUCCESS) + goto out; + + client->options = 0; + if (req->addr.family == LWRES_ADDRTYPE_V4) { + client->na.family = AF_INET; + if (req->addr.length != 4) + goto out; + memcpy(&client->na.type.in, req->addr.address, 4); + } else if (req->addr.family == LWRES_ADDRTYPE_V6) { + client->na.family = AF_INET6; + if (req->addr.length != 16) + goto out; + memcpy(&client->na.type.in6, req->addr.address, 16); + } else { + goto out; + } + isc_sockaddr_fromnetaddr(&sa, &client->na, 53); + + ns_lwdclient_log(50, "client %p looking for addrtype %08x", + client, req->addr.family); + + /* + * We no longer need to keep this around. + */ + lwres_gnbarequest_free(cm->lwctx, &req); + + /* + * Initialize the real name and alias arrays in the reply we're + * going to build up. + */ + init_gnba(client); + client->options = 0; + + /* + * Start the find. + */ + start_byaddr(client); + + return; + + /* + * We're screwed. Return an error packet to our caller. + */ + out: + if (req != NULL) + lwres_gnbarequest_free(cm->lwctx, &req); + + ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); +} diff --git a/contrib/bind-9.5.2/bin/named/lwdgrbn.c b/contrib/bind-9.5.2/bin/named/lwdgrbn.c new file mode 100644 index 0000000000..b54e83d0dd --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/lwdgrbn.c @@ -0,0 +1,513 @@ +/* + * Copyright (C) 2004-2007 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 + * 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: lwdgrbn.c,v 1.20 2007/06/19 23:46:59 tbox Exp $ */ + +/*! \file */ + +#include + +#include +#include +#include /* Required for HP/UX (and others?) */ +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static void start_lookup(ns_lwdclient_t *); + +static isc_result_t +fill_array(int *pos, dns_rdataset_t *rdataset, + int size, unsigned char **rdatas, lwres_uint16_t *rdatalen) +{ + dns_rdata_t rdata; + isc_result_t result; + isc_region_t r; + + UNUSED(size); + + dns_rdata_init(&rdata); + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) + { + INSIST(*pos < size); + dns_rdataset_current(rdataset, &rdata); + dns_rdata_toregion(&rdata, &r); + rdatas[*pos] = r.base; + rdatalen[*pos] = r.length; + dns_rdata_reset(&rdata); + (*pos)++; + } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + return (result); +} + +static isc_result_t +iterate_node(lwres_grbnresponse_t *grbn, dns_db_t *db, dns_dbnode_t *node, + isc_mem_t *mctx) +{ + int used = 0, count; + int size = 8, oldsize = 0; + unsigned char **rdatas = NULL, **oldrdatas = NULL, **newrdatas = NULL; + lwres_uint16_t *lens = NULL, *oldlens = NULL, *newlens = NULL; + dns_rdatasetiter_t *iter = NULL; + dns_rdataset_t set; + dns_ttl_t ttl = ISC_INT32_MAX; + lwres_uint32_t flags = LWRDATA_VALIDATED; + isc_result_t result = ISC_R_NOMEMORY; + + result = dns_db_allrdatasets(db, node, NULL, 0, &iter); + if (result != ISC_R_SUCCESS) + goto out; + + rdatas = isc_mem_get(mctx, size * sizeof(*rdatas)); + if (rdatas == NULL) + goto out; + lens = isc_mem_get(mctx, size * sizeof(*lens)); + if (lens == NULL) + goto out; + + for (result = dns_rdatasetiter_first(iter); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(iter)) + { + result = ISC_R_NOMEMORY; + dns_rdataset_init(&set); + dns_rdatasetiter_current(iter, &set); + + if (set.type != dns_rdatatype_rrsig) { + dns_rdataset_disassociate(&set); + continue; + } + + count = dns_rdataset_count(&set); + if (used + count > size) { + /* copy & reallocate */ + oldsize = size; + oldrdatas = rdatas; + oldlens = lens; + rdatas = NULL; + lens = NULL; + + size *= 2; + + rdatas = isc_mem_get(mctx, size * sizeof(*rdatas)); + if (rdatas == NULL) + goto out; + lens = isc_mem_get(mctx, size * sizeof(*lens)); + if (lens == NULL) + goto out; + memcpy(rdatas, oldrdatas, used * sizeof(*rdatas)); + memcpy(lens, oldlens, used * sizeof(*lens)); + isc_mem_put(mctx, oldrdatas, + oldsize * sizeof(*oldrdatas)); + isc_mem_put(mctx, oldlens, oldsize * sizeof(*oldlens)); + oldrdatas = NULL; + oldlens = NULL; + } + if (set.ttl < ttl) + ttl = set.ttl; + if (set.trust != dns_trust_secure) + flags &= (~LWRDATA_VALIDATED); + result = fill_array(&used, &set, size, rdatas, lens); + dns_rdataset_disassociate(&set); + if (result != ISC_R_SUCCESS) + goto out; + } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + if (result != ISC_R_SUCCESS) + goto out; + dns_rdatasetiter_destroy(&iter); + + /* + * If necessary, shrink and copy the arrays. + */ + if (size != used) { + result = ISC_R_NOMEMORY; + newrdatas = isc_mem_get(mctx, used * sizeof(*rdatas)); + if (newrdatas == NULL) + goto out; + newlens = isc_mem_get(mctx, used * sizeof(*lens)); + if (newlens == NULL) + goto out; + memcpy(newrdatas, rdatas, used * sizeof(*rdatas)); + memcpy(newlens, lens, used * sizeof(*lens)); + isc_mem_put(mctx, rdatas, size * sizeof(*rdatas)); + isc_mem_put(mctx, lens, size * sizeof(*lens)); + grbn->rdatas = newrdatas; + grbn->rdatalen = newlens; + } else { + grbn->rdatas = rdatas; + grbn->rdatalen = lens; + } + grbn->nrdatas = used; + grbn->ttl = ttl; + grbn->flags = flags; + return (ISC_R_SUCCESS); + + out: + dns_rdatasetiter_destroy(&iter); + if (rdatas != NULL) + isc_mem_put(mctx, rdatas, size * sizeof(*rdatas)); + if (lens != NULL) + isc_mem_put(mctx, lens, size * sizeof(*lens)); + if (oldrdatas != NULL) + isc_mem_put(mctx, oldrdatas, oldsize * sizeof(*oldrdatas)); + if (oldlens != NULL) + isc_mem_put(mctx, oldlens, oldsize * sizeof(*oldlens)); + if (newrdatas != NULL) + isc_mem_put(mctx, newrdatas, used * sizeof(*oldrdatas)); + return (result); +} + +static void +lookup_done(isc_task_t *task, isc_event_t *event) { + ns_lwdclient_t *client; + ns_lwdclientmgr_t *cm; + dns_lookupevent_t *levent; + lwres_buffer_t lwb; + dns_name_t *name; + dns_rdataset_t *rdataset; + dns_rdataset_t *sigrdataset; + isc_result_t result; + lwres_result_t lwresult; + isc_region_t r; + isc_buffer_t b; + lwres_grbnresponse_t *grbn; + int i; + + UNUSED(task); + + lwb.base = NULL; + client = event->ev_arg; + cm = client->clientmgr; + INSIST(client->lookup == (dns_lookup_t *)event->ev_sender); + + levent = (dns_lookupevent_t *)event; + grbn = &client->grbn; + + ns_lwdclient_log(50, "lookup event result = %s", + isc_result_totext(levent->result)); + + result = levent->result; + if (result != ISC_R_SUCCESS) { + dns_lookup_destroy(&client->lookup); + isc_event_free(&event); + levent = NULL; + + switch (result) { + case DNS_R_NXDOMAIN: + case DNS_R_NCACHENXDOMAIN: + result = ns_lwsearchctx_next(&client->searchctx); + if (result != ISC_R_SUCCESS) + lwresult = LWRES_R_NOTFOUND; + else { + start_lookup(client); + return; + } + break; + case DNS_R_NXRRSET: + case DNS_R_NCACHENXRRSET: + lwresult = LWRES_R_TYPENOTFOUND; + break; + default: + lwresult = LWRES_R_FAILURE; + } + ns_lwdclient_errorpktsend(client, lwresult); + return; + } + + name = levent->name; + b = client->recv_buffer; + + grbn->flags = 0; + + grbn->nrdatas = 0; + grbn->rdatas = NULL; + grbn->rdatalen = NULL; + + grbn->nsigs = 0; + grbn->sigs = NULL; + grbn->siglen = NULL; + + result = dns_name_totext(name, ISC_TRUE, &client->recv_buffer); + if (result != ISC_R_SUCCESS) + goto out; + grbn->realname = (char *)isc_buffer_used(&b); + grbn->realnamelen = isc_buffer_usedlength(&client->recv_buffer) - + isc_buffer_usedlength(&b); + ns_lwdclient_log(50, "found name '%.*s'", grbn->realnamelen, + grbn->realname); + + grbn->rdclass = cm->view->rdclass; + grbn->rdtype = client->rdtype; + + rdataset = levent->rdataset; + if (rdataset != NULL) { + /* The normal case */ + grbn->nrdatas = dns_rdataset_count(rdataset); + grbn->rdatas = isc_mem_get(cm->mctx, grbn->nrdatas * + sizeof(unsigned char *)); + if (grbn->rdatas == NULL) + goto out; + grbn->rdatalen = isc_mem_get(cm->mctx, grbn->nrdatas * + sizeof(lwres_uint16_t)); + if (grbn->rdatalen == NULL) + goto out; + + i = 0; + result = fill_array(&i, rdataset, grbn->nrdatas, grbn->rdatas, + grbn->rdatalen); + if (result != ISC_R_SUCCESS) + goto out; + INSIST(i == grbn->nrdatas); + grbn->ttl = rdataset->ttl; + if (rdataset->trust == dns_trust_secure) + grbn->flags |= LWRDATA_VALIDATED; + } else { + /* The SIG query case */ + result = iterate_node(grbn, levent->db, levent->node, + cm->mctx); + if (result != ISC_R_SUCCESS) + goto out; + } + ns_lwdclient_log(50, "filled in %d rdata%s", grbn->nrdatas, + (grbn->nrdatas == 1) ? "" : "s"); + + sigrdataset = levent->sigrdataset; + if (sigrdataset != NULL) { + grbn->nsigs = dns_rdataset_count(sigrdataset); + grbn->sigs = isc_mem_get(cm->mctx, grbn->nsigs * + sizeof(unsigned char *)); + if (grbn->sigs == NULL) + goto out; + grbn->siglen = isc_mem_get(cm->mctx, grbn->nsigs * + sizeof(lwres_uint16_t)); + if (grbn->siglen == NULL) + goto out; + + i = 0; + result = fill_array(&i, sigrdataset, grbn->nsigs, grbn->sigs, + grbn->siglen); + if (result != ISC_R_SUCCESS) + goto out; + INSIST(i == grbn->nsigs); + ns_lwdclient_log(50, "filled in %d signature%s", grbn->nsigs, + (grbn->nsigs == 1) ? "" : "s"); + } + + dns_lookup_destroy(&client->lookup); + isc_event_free(&event); + + /* + * Render the packet. + */ + client->pkt.recvlength = LWRES_RECVLENGTH; + client->pkt.authtype = 0; /* XXXMLG */ + client->pkt.authlength = 0; + client->pkt.result = LWRES_R_SUCCESS; + + lwresult = lwres_grbnresponse_render(cm->lwctx, + grbn, &client->pkt, &lwb); + if (lwresult != LWRES_R_SUCCESS) + goto out; + + isc_mem_put(cm->mctx, grbn->rdatas, + grbn->nrdatas * sizeof(unsigned char *)); + isc_mem_put(cm->mctx, grbn->rdatalen, + grbn->nrdatas * sizeof(lwres_uint16_t)); + + if (grbn->sigs != NULL) + isc_mem_put(cm->mctx, grbn->sigs, + grbn->nsigs * sizeof(unsigned char *)); + if (grbn->siglen != NULL) + isc_mem_put(cm->mctx, grbn->siglen, + grbn->nsigs * sizeof(lwres_uint16_t)); + + r.base = lwb.base; + r.length = lwb.used; + client->sendbuf = r.base; + client->sendlength = r.length; + result = ns_lwdclient_sendreply(client, &r); + if (result != ISC_R_SUCCESS) + goto out2; + + NS_LWDCLIENT_SETSEND(client); + + return; + + out: + if (grbn->rdatas != NULL) + isc_mem_put(cm->mctx, grbn->rdatas, + grbn->nrdatas * sizeof(unsigned char *)); + if (grbn->rdatalen != NULL) + isc_mem_put(cm->mctx, grbn->rdatalen, + grbn->nrdatas * sizeof(lwres_uint16_t)); + + if (grbn->sigs != NULL) + isc_mem_put(cm->mctx, grbn->sigs, + grbn->nsigs * sizeof(unsigned char *)); + if (grbn->siglen != NULL) + isc_mem_put(cm->mctx, grbn->siglen, + grbn->nsigs * sizeof(lwres_uint16_t)); + out2: + if (client->lookup != NULL) + dns_lookup_destroy(&client->lookup); + if (lwb.base != NULL) + lwres_context_freemem(cm->lwctx, lwb.base, lwb.length); + + if (event != NULL) + isc_event_free(&event); + + ns_lwdclient_log(50, "error constructing getrrsetbyname response"); + ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); +} + +static void +start_lookup(ns_lwdclient_t *client) { + isc_result_t result; + ns_lwdclientmgr_t *cm; + dns_fixedname_t absname; + + cm = client->clientmgr; + + INSIST(client->lookup == NULL); + + dns_fixedname_init(&absname); + result = ns_lwsearchctx_current(&client->searchctx, + dns_fixedname_name(&absname)); + /* + * This will return failure if relative name + suffix is too long. + * In this case, just go on to the next entry in the search path. + */ + if (result != ISC_R_SUCCESS) + start_lookup(client); + + result = dns_lookup_create(cm->mctx, + dns_fixedname_name(&absname), + client->rdtype, cm->view, + client->options, cm->task, lookup_done, + client, &client->lookup); + if (result != ISC_R_SUCCESS) { + ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); + return; + } +} + +static void +init_grbn(ns_lwdclient_t *client) { + client->grbn.rdclass = 0; + client->grbn.rdtype = 0; + client->grbn.ttl = 0; + client->grbn.nrdatas = 0; + client->grbn.realname = NULL; + client->grbn.realnamelen = 0; + client->grbn.rdatas = 0; + client->grbn.rdatalen = 0; + client->grbn.base = NULL; + client->grbn.baselen = 0; + isc_buffer_init(&client->recv_buffer, client->buffer, LWRES_RECVLENGTH); +} + +void +ns_lwdclient_processgrbn(ns_lwdclient_t *client, lwres_buffer_t *b) { + lwres_grbnrequest_t *req; + isc_result_t result; + ns_lwdclientmgr_t *cm; + isc_buffer_t namebuf; + + REQUIRE(NS_LWDCLIENT_ISRECVDONE(client)); + INSIST(client->byaddr == NULL); + + cm = client->clientmgr; + req = NULL; + + result = lwres_grbnrequest_parse(cm->lwctx, + b, &client->pkt, &req); + if (result != LWRES_R_SUCCESS) + goto out; + if (req->name == NULL) + goto out; + + client->options = 0; + if (req->rdclass != cm->view->rdclass) + goto out; + + if (req->rdclass == dns_rdataclass_any || + req->rdtype == dns_rdatatype_any) + goto out; + + client->rdtype = req->rdtype; + + isc_buffer_init(&namebuf, req->name, req->namelen); + isc_buffer_add(&namebuf, req->namelen); + + dns_fixedname_init(&client->query_name); + result = dns_name_fromtext(dns_fixedname_name(&client->query_name), + &namebuf, NULL, ISC_FALSE, NULL); + if (result != ISC_R_SUCCESS) + goto out; + ns_lwsearchctx_init(&client->searchctx, + cm->listener->manager->search, + dns_fixedname_name(&client->query_name), + cm->listener->manager->ndots); + ns_lwsearchctx_first(&client->searchctx); + + ns_lwdclient_log(50, "client %p looking for type %d", + client, client->rdtype); + + /* + * We no longer need to keep this around. + */ + lwres_grbnrequest_free(cm->lwctx, &req); + + /* + * Initialize the real name and alias arrays in the reply we're + * going to build up. + */ + init_grbn(client); + + /* + * Start the find. + */ + start_lookup(client); + + return; + + /* + * We're screwed. Return an error packet to our caller. + */ + out: + if (req != NULL) + lwres_grbnrequest_free(cm->lwctx, &req); + + ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); +} diff --git a/contrib/bind-9.5.2/bin/named/lwdnoop.c b/contrib/bind-9.5.2/bin/named/lwdnoop.c new file mode 100644 index 0000000000..b01deeba80 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/lwdnoop.c @@ -0,0 +1,87 @@ +/* + * 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 + * 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: lwdnoop.c,v 1.11.130.2 2008/01/22 23:27:35 tbox Exp $ */ + +/*! \file */ + +#include + +#include +#include + +#include +#include + +void +ns_lwdclient_processnoop(ns_lwdclient_t *client, lwres_buffer_t *b) { + lwres_nooprequest_t *req; + lwres_noopresponse_t resp; + isc_result_t result; + lwres_result_t lwres; + isc_region_t r; + lwres_buffer_t lwb; + + REQUIRE(NS_LWDCLIENT_ISRECVDONE(client)); + INSIST(client->byaddr == NULL); + + req = NULL; + + result = lwres_nooprequest_parse(client->clientmgr->lwctx, + b, &client->pkt, &req); + if (result != LWRES_R_SUCCESS) + goto send_error; + + client->pkt.recvlength = LWRES_RECVLENGTH; + client->pkt.authtype = 0; /* XXXMLG */ + client->pkt.authlength = 0; + client->pkt.result = LWRES_R_SUCCESS; + + resp.datalength = req->datalength; + resp.data = req->data; + + lwres = lwres_noopresponse_render(client->clientmgr->lwctx, &resp, + &client->pkt, &lwb); + if (lwres != LWRES_R_SUCCESS) + goto cleanup_req; + + r.base = lwb.base; + r.length = lwb.used; + client->sendbuf = r.base; + client->sendlength = r.length; + result = ns_lwdclient_sendreply(client, &r); + if (result != ISC_R_SUCCESS) + goto cleanup_lwb; + + /* + * We can now destroy request. + */ + lwres_nooprequest_free(client->clientmgr->lwctx, &req); + + NS_LWDCLIENT_SETSEND(client); + + return; + + cleanup_lwb: + lwres_context_freemem(client->clientmgr->lwctx, lwb.base, lwb.length); + + cleanup_req: + lwres_nooprequest_free(client->clientmgr->lwctx, &req); + + send_error: + ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); +} diff --git a/contrib/bind-9.5.2/bin/named/lwresd.8 b/contrib/bind-9.5.2/bin/named/lwresd.8 new file mode 100644 index 0000000000..805e40c19b --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/lwresd.8 @@ -0,0 +1,223 @@ +.\" 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 +.\" 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: lwresd.8,v 1.27.150.3 2009/07/11 01:43:27 tbox Exp $ +.\" +.hy 0 +.ad l +.\" Title: lwresd +.\" Author: +.\" Generator: DocBook XSL Stylesheets v1.71.1 +.\" Date: June 30, 2000 +.\" Manual: BIND9 +.\" Source: BIND9 +.\" +.TH "LWRESD" "8" "June 30, 2000" "BIND9" "BIND9" +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.SH "NAME" +lwresd \- lightweight resolver daemon +.SH "SYNOPSIS" +.HP 7 +\fBlwresd\fR [\fB\-c\ \fR\fB\fIconfig\-file\fR\fR] [\fB\-C\ \fR\fB\fIconfig\-file\fR\fR] [\fB\-d\ \fR\fB\fIdebug\-level\fR\fR] [\fB\-f\fR] [\fB\-g\fR] [\fB\-i\ \fR\fB\fIpid\-file\fR\fR] [\fB\-m\ \fR\fB\fIflag\fR\fR] [\fB\-n\ \fR\fB\fI#cpus\fR\fR] [\fB\-P\ \fR\fB\fIport\fR\fR] [\fB\-p\ \fR\fB\fIport\fR\fR] [\fB\-s\fR] [\fB\-t\ \fR\fB\fIdirectory\fR\fR] [\fB\-u\ \fR\fB\fIuser\fR\fR] [\fB\-v\fR] [\fB\-4\fR] [\fB\-6\fR] +.SH "DESCRIPTION" +.PP +\fBlwresd\fR +is the daemon providing name lookup services to clients that use the BIND 9 lightweight resolver library. It is essentially a stripped\-down, caching\-only name server that answers queries using the BIND 9 lightweight resolver protocol rather than the DNS protocol. +.PP +\fBlwresd\fR +listens for resolver queries on a UDP port on the IPv4 loopback interface, 127.0.0.1. This means that +\fBlwresd\fR +can only be used by processes running on the local machine. By default, UDP port number 921 is used for lightweight resolver requests and responses. +.PP +Incoming lightweight resolver requests are decoded by the server which then resolves them using the DNS protocol. When the DNS lookup completes, +\fBlwresd\fR +encodes the answers in the lightweight resolver format and returns them to the client that made the request. +.PP +If +\fI/etc/resolv.conf\fR +contains any +\fBnameserver\fR +entries, +\fBlwresd\fR +sends recursive DNS queries to those servers. This is similar to the use of forwarders in a caching name server. If no +\fBnameserver\fR +entries are present, or if forwarding fails, +\fBlwresd\fR +resolves the queries autonomously starting at the root name servers, using a built\-in list of root server hints. +.SH "OPTIONS" +.PP +\-4 +.RS 4 +Use IPv4 only even if the host machine is capable of IPv6. +\fB\-4\fR +and +\fB\-6\fR +are mutually exclusive. +.RE +.PP +\-6 +.RS 4 +Use IPv6 only even if the host machine is capable of IPv4. +\fB\-4\fR +and +\fB\-6\fR +are mutually exclusive. +.RE +.PP +\-c \fIconfig\-file\fR +.RS 4 +Use +\fIconfig\-file\fR +as the configuration file instead of the default, +\fI/etc/lwresd.conf\fR. +\fB\-c\fR +can not be used with +\fB\-C\fR. +.RE +.PP +\-C \fIconfig\-file\fR +.RS 4 +Use +\fIconfig\-file\fR +as the configuration file instead of the default, +\fI/etc/resolv.conf\fR. +\fB\-C\fR +can not be used with +\fB\-c\fR. +.RE +.PP +\-d \fIdebug\-level\fR +.RS 4 +Set the daemon's debug level to +\fIdebug\-level\fR. Debugging traces from +\fBlwresd\fR +become more verbose as the debug level increases. +.RE +.PP +\-f +.RS 4 +Run the server in the foreground (i.e. do not daemonize). +.RE +.PP +\-g +.RS 4 +Run the server in the foreground and force all logging to +\fIstderr\fR. +.RE +.PP +\-i \fIpid\-file\fR +.RS 4 +Use +\fIpid\-file\fR +as the PID file instead of the default, +\fI/var/run/lwresd.pid\fR. +.RE +.PP +\-m \fIflag\fR +.RS 4 +Turn on memory usage debugging flags. Possible flags are +\fIusage\fR, +\fItrace\fR, +\fIrecord\fR, +\fIsize\fR, and +\fImctx\fR. These correspond to the ISC_MEM_DEBUGXXXX flags described in +\fI\fR. +.RE +.PP +\-n \fI#cpus\fR +.RS 4 +Create +\fI#cpus\fR +worker threads to take advantage of multiple CPUs. If not specified, +\fBlwresd\fR +will try to determine the number of CPUs present and create one thread per CPU. If it is unable to determine the number of CPUs, a single worker thread will be created. +.RE +.PP +\-P \fIport\fR +.RS 4 +Listen for lightweight resolver queries on port +\fIport\fR. If not specified, the default is port 921. +.RE +.PP +\-p \fIport\fR +.RS 4 +Send DNS lookups to port +\fIport\fR. If not specified, the default is port 53. This provides a way of testing the lightweight resolver daemon with a name server that listens for queries on a non\-standard port number. +.RE +.PP +\-s +.RS 4 +Write memory usage statistics to +\fIstdout\fR +on exit. +.RS +.B "Note:" +This option is mainly of interest to BIND 9 developers and may be removed or changed in a future release. +.RE +.RE +.PP +\-t \fIdirectory\fR +.RS 4 +Chroot to +\fIdirectory\fR +after processing the command line arguments, but before reading the configuration file. +.RS +.B "Warning:" +This option should be used in conjunction with the +\fB\-u\fR +option, as chrooting a process running as root doesn't enhance security on most systems; the way +\fBchroot(2)\fR +is defined allows a process with root privileges to escape a chroot jail. +.RE +.RE +.PP +\-u \fIuser\fR +.RS 4 +Setuid to +\fIuser\fR +after completing privileged operations, such as creating sockets that listen on privileged ports. +.RE +.PP +\-v +.RS 4 +Report the version number and exit. +.RE +.SH "FILES" +.PP +\fI/etc/resolv.conf\fR +.RS 4 +The default configuration file. +.RE +.PP +\fI/var/run/lwresd.pid\fR +.RS 4 +The default process\-id file. +.RE +.SH "SEE ALSO" +.PP +\fBnamed\fR(8), +\fBlwres\fR(3), +\fBresolver\fR(5). +.SH "AUTHOR" +.PP +Internet Systems Consortium +.SH "COPYRIGHT" +Copyright \(co 2004, 2005, 2007\-2009 Internet Systems Consortium, Inc. ("ISC") +.br +Copyright \(co 2000, 2001 Internet Software Consortium. +.br diff --git a/contrib/bind-9.5.2/bin/named/lwresd.c b/contrib/bind-9.5.2/bin/named/lwresd.c new file mode 100644 index 0000000000..93409faaf5 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/lwresd.c @@ -0,0 +1,870 @@ +/* + * 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 + * 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: lwresd.c,v 1.55.130.3 2008/07/23 23:31:17 marka Exp $ */ + +/*! \file + * \brief + * Main program for the Lightweight Resolver Daemon. + * + * To paraphrase the old saying about X11, "It's not a lightweight deamon + * for resolvers, it's a deamon for lightweight resolvers". + */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define LWRESD_MAGIC ISC_MAGIC('L', 'W', 'R', 'D') +#define VALID_LWRESD(l) ISC_MAGIC_VALID(l, LWRESD_MAGIC) + +#define LWRESLISTENER_MAGIC ISC_MAGIC('L', 'W', 'R', 'L') +#define VALID_LWRESLISTENER(l) ISC_MAGIC_VALID(l, LWRESLISTENER_MAGIC) + +/*! + * The total number of clients we can handle will be NTASKS * NRECVS. + */ +#define NTASKS 2 /*%< tasks to create to handle lwres queries */ +#define NRECVS 2 /*%< max clients per task */ + +typedef ISC_LIST(ns_lwreslistener_t) ns_lwreslistenerlist_t; + +static ns_lwreslistenerlist_t listeners; +static isc_mutex_t listeners_lock; +static isc_once_t once = ISC_ONCE_INIT; + + +static void +initialize_mutex(void) { + RUNTIME_CHECK(isc_mutex_init(&listeners_lock) == ISC_R_SUCCESS); +} + + +/*% + * Wrappers around our memory management stuff, for the lwres functions. + */ +void * +ns__lwresd_memalloc(void *arg, size_t size) { + return (isc_mem_get(arg, size)); +} + +void +ns__lwresd_memfree(void *arg, void *mem, size_t size) { + isc_mem_put(arg, mem, size); +} + + +#define CHECK(op) \ + do { result = (op); \ + if (result != ISC_R_SUCCESS) goto cleanup; \ + } while (0) + +static isc_result_t +buffer_putstr(isc_buffer_t *b, const char *s) { + unsigned int len = strlen(s); + if (isc_buffer_availablelength(b) <= len) + return (ISC_R_NOSPACE); + isc_buffer_putmem(b, (const unsigned char *)s, len); + return (ISC_R_SUCCESS); +} + +/* + * Convert a resolv.conf file into a config structure. + */ +isc_result_t +ns_lwresd_parseeresolvconf(isc_mem_t *mctx, cfg_parser_t *pctx, + cfg_obj_t **configp) +{ + char text[4096]; + char str[16]; + isc_buffer_t b; + lwres_context_t *lwctx = NULL; + lwres_conf_t *lwc = NULL; + isc_sockaddr_t sa; + isc_netaddr_t na; + int i; + isc_result_t result; + lwres_result_t lwresult; + + lwctx = NULL; + lwresult = lwres_context_create(&lwctx, mctx, ns__lwresd_memalloc, + ns__lwresd_memfree, + LWRES_CONTEXT_SERVERMODE); + if (lwresult != LWRES_R_SUCCESS) { + result = ISC_R_NOMEMORY; + goto cleanup; + } + + lwresult = lwres_conf_parse(lwctx, lwresd_g_resolvconffile); + if (lwresult != LWRES_R_SUCCESS) { + result = DNS_R_SYNTAX; + goto cleanup; + } + + lwc = lwres_conf_get(lwctx); + INSIST(lwc != NULL); + + isc_buffer_init(&b, text, sizeof(text)); + + CHECK(buffer_putstr(&b, "options {\n")); + + /* + * Build the list of forwarders. + */ + if (lwc->nsnext > 0) { + CHECK(buffer_putstr(&b, "\tforwarders {\n")); + + for (i = 0; i < lwc->nsnext; i++) { + CHECK(lwaddr_sockaddr_fromlwresaddr( + &sa, + &lwc->nameservers[i], + ns_g_port)); + isc_netaddr_fromsockaddr(&na, &sa); + CHECK(buffer_putstr(&b, "\t\t")); + CHECK(isc_netaddr_totext(&na, &b)); + CHECK(buffer_putstr(&b, ";\n")); + } + CHECK(buffer_putstr(&b, "\t};\n")); + } + + /* + * Build the sortlist + */ + if (lwc->sortlistnxt > 0) { + CHECK(buffer_putstr(&b, "\tsortlist {\n")); + CHECK(buffer_putstr(&b, "\t\t{\n")); + CHECK(buffer_putstr(&b, "\t\t\tany;\n")); + CHECK(buffer_putstr(&b, "\t\t\t{\n")); + for (i = 0; i < lwc->sortlistnxt; i++) { + lwres_addr_t *lwaddr = &lwc->sortlist[i].addr; + lwres_addr_t *lwmask = &lwc->sortlist[i].mask; + unsigned int mask; + + CHECK(lwaddr_sockaddr_fromlwresaddr(&sa, lwmask, 0)); + isc_netaddr_fromsockaddr(&na, &sa); + result = isc_netaddr_masktoprefixlen(&na, &mask); + if (result != ISC_R_SUCCESS) { + char addrtext[ISC_NETADDR_FORMATSIZE]; + isc_netaddr_format(&na, addrtext, + sizeof(addrtext)); + isc_log_write(ns_g_lctx, + NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_LWRESD, + ISC_LOG_ERROR, + "processing sortlist: '%s' is " + "not a valid netmask", + addrtext); + goto cleanup; + } + + CHECK(lwaddr_sockaddr_fromlwresaddr(&sa, lwaddr, 0)); + isc_netaddr_fromsockaddr(&na, &sa); + + CHECK(buffer_putstr(&b, "\t\t\t\t")); + CHECK(isc_netaddr_totext(&na, &b)); + snprintf(str, sizeof(str), "%u", mask); + CHECK(buffer_putstr(&b, "/")); + CHECK(buffer_putstr(&b, str)); + CHECK(buffer_putstr(&b, ";\n")); + } + CHECK(buffer_putstr(&b, "\t\t\t};\n")); + CHECK(buffer_putstr(&b, "\t\t};\n")); + CHECK(buffer_putstr(&b, "\t};\n")); + } + + CHECK(buffer_putstr(&b, "};\n\n")); + + CHECK(buffer_putstr(&b, "lwres {\n")); + + /* + * Build the search path + */ + if (lwc->searchnxt > 0) { + if (lwc->searchnxt > 0) { + CHECK(buffer_putstr(&b, "\tsearch {\n")); + for (i = 0; i < lwc->searchnxt; i++) { + CHECK(buffer_putstr(&b, "\t\t\"")); + CHECK(buffer_putstr(&b, lwc->search[i])); + CHECK(buffer_putstr(&b, "\";\n")); + } + CHECK(buffer_putstr(&b, "\t};\n")); + } + } + + /* + * Build the ndots line + */ + if (lwc->ndots != 1) { + CHECK(buffer_putstr(&b, "\tndots ")); + snprintf(str, sizeof(str), "%u", lwc->ndots); + CHECK(buffer_putstr(&b, str)); + CHECK(buffer_putstr(&b, ";\n")); + } + + /* + * Build the listen-on line + */ + if (lwc->lwnext > 0) { + CHECK(buffer_putstr(&b, "\tlisten-on {\n")); + + for (i = 0; i < lwc->lwnext; i++) { + CHECK(lwaddr_sockaddr_fromlwresaddr(&sa, + &lwc->lwservers[i], + 0)); + isc_netaddr_fromsockaddr(&na, &sa); + CHECK(buffer_putstr(&b, "\t\t")); + CHECK(isc_netaddr_totext(&na, &b)); + CHECK(buffer_putstr(&b, ";\n")); + } + CHECK(buffer_putstr(&b, "\t};\n")); + } + + CHECK(buffer_putstr(&b, "};\n")); + +#if 0 + printf("%.*s\n", + (int)isc_buffer_usedlength(&b), + (char *)isc_buffer_base(&b)); +#endif + + lwres_conf_clear(lwctx); + lwres_context_destroy(&lwctx); + + return (cfg_parse_buffer(pctx, &b, &cfg_type_namedconf, configp)); + + cleanup: + + if (lwctx != NULL) { + lwres_conf_clear(lwctx); + lwres_context_destroy(&lwctx); + } + + return (result); +} + + +/* + * Handle lwresd manager objects + */ +isc_result_t +ns_lwdmanager_create(isc_mem_t *mctx, const cfg_obj_t *lwres, + ns_lwresd_t **lwresdp) +{ + ns_lwresd_t *lwresd; + const char *vname; + dns_rdataclass_t vclass; + const cfg_obj_t *obj, *viewobj, *searchobj; + const cfg_listelt_t *element; + isc_result_t result; + + INSIST(lwresdp != NULL && *lwresdp == NULL); + + lwresd = isc_mem_get(mctx, sizeof(ns_lwresd_t)); + if (lwresd == NULL) + return (ISC_R_NOMEMORY); + + lwresd->mctx = NULL; + isc_mem_attach(mctx, &lwresd->mctx); + lwresd->view = NULL; + lwresd->search = NULL; + lwresd->refs = 1; + + obj = NULL; + (void)cfg_map_get(lwres, "ndots", &obj); + if (obj != NULL) + lwresd->ndots = cfg_obj_asuint32(obj); + else + lwresd->ndots = 1; + + RUNTIME_CHECK(isc_mutex_init(&lwresd->lock) == ISC_R_SUCCESS); + + lwresd->shutting_down = ISC_FALSE; + + viewobj = NULL; + (void)cfg_map_get(lwres, "view", &viewobj); + if (viewobj != NULL) { + vname = cfg_obj_asstring(cfg_tuple_get(viewobj, "name")); + obj = cfg_tuple_get(viewobj, "class"); + result = ns_config_getclass(obj, dns_rdataclass_in, &vclass); + if (result != ISC_R_SUCCESS) + goto fail; + } else { + vname = "_default"; + vclass = dns_rdataclass_in; + } + + result = dns_viewlist_find(&ns_g_server->viewlist, vname, vclass, + &lwresd->view); + if (result != ISC_R_SUCCESS) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_LWRESD, ISC_LOG_WARNING, + "couldn't find view %s", vname); + goto fail; + } + + searchobj = NULL; + (void)cfg_map_get(lwres, "search", &searchobj); + if (searchobj != NULL) { + lwresd->search = NULL; + result = ns_lwsearchlist_create(lwresd->mctx, + &lwresd->search); + if (result != ISC_R_SUCCESS) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_LWRESD, ISC_LOG_WARNING, + "couldn't create searchlist"); + goto fail; + } + for (element = cfg_list_first(searchobj); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *search; + const char *searchstr; + isc_buffer_t namebuf; + dns_fixedname_t fname; + dns_name_t *name; + + search = cfg_listelt_value(element); + searchstr = cfg_obj_asstring(search); + + dns_fixedname_init(&fname); + name = dns_fixedname_name(&fname); + isc_buffer_init(&namebuf, searchstr, + strlen(searchstr)); + isc_buffer_add(&namebuf, strlen(searchstr)); + result = dns_name_fromtext(name, &namebuf, + dns_rootname, ISC_FALSE, + NULL); + if (result != ISC_R_SUCCESS) { + isc_log_write(ns_g_lctx, + NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_LWRESD, + ISC_LOG_WARNING, + "invalid name %s in searchlist", + searchstr); + continue; + } + + result = ns_lwsearchlist_append(lwresd->search, name); + if (result != ISC_R_SUCCESS) { + isc_log_write(ns_g_lctx, + NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_LWRESD, + ISC_LOG_WARNING, + "couldn't update searchlist"); + goto fail; + } + } + } + + lwresd->magic = LWRESD_MAGIC; + + *lwresdp = lwresd; + return (ISC_R_SUCCESS); + + fail: + if (lwresd->view != NULL) + dns_view_detach(&lwresd->view); + if (lwresd->search != NULL) + ns_lwsearchlist_detach(&lwresd->search); + if (lwresd->mctx != NULL) + isc_mem_detach(&lwresd->mctx); + isc_mem_put(mctx, lwresd, sizeof(ns_lwresd_t)); + return (result); +} + +void +ns_lwdmanager_attach(ns_lwresd_t *source, ns_lwresd_t **targetp) { + INSIST(VALID_LWRESD(source)); + INSIST(targetp != NULL && *targetp == NULL); + + LOCK(&source->lock); + source->refs++; + UNLOCK(&source->lock); + + *targetp = source; +} + +void +ns_lwdmanager_detach(ns_lwresd_t **lwresdp) { + ns_lwresd_t *lwresd; + isc_mem_t *mctx; + isc_boolean_t done = ISC_FALSE; + + INSIST(lwresdp != NULL && *lwresdp != NULL); + INSIST(VALID_LWRESD(*lwresdp)); + + lwresd = *lwresdp; + *lwresdp = NULL; + + LOCK(&lwresd->lock); + INSIST(lwresd->refs > 0); + lwresd->refs--; + if (lwresd->refs == 0) + done = ISC_TRUE; + UNLOCK(&lwresd->lock); + + if (!done) + return; + + dns_view_detach(&lwresd->view); + if (lwresd->search != NULL) + ns_lwsearchlist_detach(&lwresd->search); + mctx = lwresd->mctx; + lwresd->magic = 0; + isc_mem_put(mctx, lwresd, sizeof(*lwresd)); + isc_mem_detach(&mctx); +} + + +/* + * Handle listener objects + */ +void +ns_lwreslistener_attach(ns_lwreslistener_t *source, + ns_lwreslistener_t **targetp) +{ + INSIST(VALID_LWRESLISTENER(source)); + INSIST(targetp != NULL && *targetp == NULL); + + LOCK(&source->lock); + source->refs++; + UNLOCK(&source->lock); + + *targetp = source; +} + +void +ns_lwreslistener_detach(ns_lwreslistener_t **listenerp) { + ns_lwreslistener_t *listener; + isc_mem_t *mctx; + isc_boolean_t done = ISC_FALSE; + + INSIST(listenerp != NULL && *listenerp != NULL); + INSIST(VALID_LWRESLISTENER(*listenerp)); + + listener = *listenerp; + + LOCK(&listener->lock); + INSIST(listener->refs > 0); + listener->refs--; + if (listener->refs == 0) + done = ISC_TRUE; + UNLOCK(&listener->lock); + + if (!done) + return; + + if (listener->manager != NULL) + ns_lwdmanager_detach(&listener->manager); + + if (listener->sock != NULL) + isc_socket_detach(&listener->sock); + + listener->magic = 0; + mctx = listener->mctx; + isc_mem_put(mctx, listener, sizeof(*listener)); + isc_mem_detach(&mctx); + listenerp = NULL; +} + +static isc_result_t +listener_create(isc_mem_t *mctx, ns_lwresd_t *lwresd, + ns_lwreslistener_t **listenerp) +{ + ns_lwreslistener_t *listener; + isc_result_t result; + + REQUIRE(listenerp != NULL && *listenerp == NULL); + + listener = isc_mem_get(mctx, sizeof(ns_lwreslistener_t)); + if (listener == NULL) + return (ISC_R_NOMEMORY); + + result = isc_mutex_init(&listener->lock); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, listener, sizeof(ns_lwreslistener_t)); + return (result); + } + + listener->magic = LWRESLISTENER_MAGIC; + listener->refs = 1; + + listener->sock = NULL; + + listener->manager = NULL; + ns_lwdmanager_attach(lwresd, &listener->manager); + + listener->mctx = NULL; + isc_mem_attach(mctx, &listener->mctx); + + ISC_LINK_INIT(listener, link); + ISC_LIST_INIT(listener->cmgrs); + + *listenerp = listener; + return (ISC_R_SUCCESS); +} + +static isc_result_t +listener_bind(ns_lwreslistener_t *listener, isc_sockaddr_t *address) { + isc_socket_t *sock = NULL; + isc_result_t result = ISC_R_SUCCESS; + int pf; + + pf = isc_sockaddr_pf(address); + if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) || + (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS)) + return (ISC_R_FAMILYNOSUPPORT); + + listener->address = *address; + + if (isc_sockaddr_getport(&listener->address) == 0) { + in_port_t port; + port = lwresd_g_listenport; + if (port == 0) + port = LWRES_UDP_PORT; + isc_sockaddr_setport(&listener->address, port); + } + + sock = NULL; + result = isc_socket_create(ns_g_socketmgr, pf, + isc_sockettype_udp, &sock); + if (result != ISC_R_SUCCESS) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_LWRESD, ISC_LOG_WARNING, + "failed to create lwres socket: %s", + isc_result_totext(result)); + return (result); + } + + result = isc_socket_bind(sock, &listener->address, + ISC_SOCKET_REUSEADDRESS); + if (result != ISC_R_SUCCESS) { + char socktext[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_format(&listener->address, socktext, + sizeof(socktext)); + isc_socket_detach(&sock); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_LWRESD, ISC_LOG_WARNING, + "failed to add lwres socket: %s: %s", + socktext, isc_result_totext(result)); + return (result); + } + listener->sock = sock; + return (ISC_R_SUCCESS); +} + +static void +listener_copysock(ns_lwreslistener_t *oldlistener, + ns_lwreslistener_t *newlistener) +{ + newlistener->address = oldlistener->address; + isc_socket_attach(oldlistener->sock, &newlistener->sock); +} + +static isc_result_t +listener_startclients(ns_lwreslistener_t *listener) { + ns_lwdclientmgr_t *cm; + unsigned int i; + isc_result_t result; + + /* + * Create the client managers. + */ + result = ISC_R_SUCCESS; + for (i = 0; i < NTASKS && result == ISC_R_SUCCESS; i++) + result = ns_lwdclientmgr_create(listener, NRECVS, + ns_g_taskmgr); + + /* + * Ensure that we have created at least one. + */ + if (ISC_LIST_EMPTY(listener->cmgrs)) + return (result); + + /* + * Walk the list of clients and start each one up. + */ + LOCK(&listener->lock); + cm = ISC_LIST_HEAD(listener->cmgrs); + while (cm != NULL) { + result = ns_lwdclient_startrecv(cm); + if (result != ISC_R_SUCCESS) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_LWRESD, ISC_LOG_ERROR, + "could not start lwres " + "client handler: %s", + isc_result_totext(result)); + cm = ISC_LIST_NEXT(cm, link); + } + UNLOCK(&listener->lock); + + return (ISC_R_SUCCESS); +} + +static void +listener_shutdown(ns_lwreslistener_t *listener) { + ns_lwdclientmgr_t *cm; + + cm = ISC_LIST_HEAD(listener->cmgrs); + while (cm != NULL) { + isc_task_shutdown(cm->task); + cm = ISC_LIST_NEXT(cm, link); + } +} + +static isc_result_t +find_listener(isc_sockaddr_t *address, ns_lwreslistener_t **listenerp) { + ns_lwreslistener_t *listener; + + INSIST(listenerp != NULL && *listenerp == NULL); + + for (listener = ISC_LIST_HEAD(listeners); + listener != NULL; + listener = ISC_LIST_NEXT(listener, link)) + { + if (!isc_sockaddr_equal(address, &listener->address)) + continue; + *listenerp = listener; + return (ISC_R_SUCCESS); + } + return (ISC_R_NOTFOUND); +} + +void +ns_lwreslistener_unlinkcm(ns_lwreslistener_t *listener, ns_lwdclientmgr_t *cm) +{ + REQUIRE(VALID_LWRESLISTENER(listener)); + + LOCK(&listener->lock); + ISC_LIST_UNLINK(listener->cmgrs, cm, link); + UNLOCK(&listener->lock); +} + +void +ns_lwreslistener_linkcm(ns_lwreslistener_t *listener, ns_lwdclientmgr_t *cm) { + REQUIRE(VALID_LWRESLISTENER(listener)); + + /* + * This does no locking, since it's called early enough that locking + * isn't needed. + */ + ISC_LIST_APPEND(listener->cmgrs, cm, link); +} + +static isc_result_t +configure_listener(isc_sockaddr_t *address, ns_lwresd_t *lwresd, + isc_mem_t *mctx, ns_lwreslistenerlist_t *newlisteners) +{ + ns_lwreslistener_t *listener, *oldlistener = NULL; + char socktext[ISC_SOCKADDR_FORMATSIZE]; + isc_result_t result; + + (void)find_listener(address, &oldlistener); + listener = NULL; + result = listener_create(mctx, lwresd, &listener); + if (result != ISC_R_SUCCESS) { + isc_sockaddr_format(address, socktext, sizeof(socktext)); + isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL, + NS_LOGMODULE_LWRESD, ISC_LOG_WARNING, + "lwres failed to configure %s: %s", + socktext, isc_result_totext(result)); + return (result); + } + + /* + * If there's already a listener, don't rebind the socket. + */ + if (oldlistener == NULL) { + result = listener_bind(listener, address); + if (result != ISC_R_SUCCESS) { + ns_lwreslistener_detach(&listener); + return (ISC_R_SUCCESS); + } + } else + listener_copysock(oldlistener, listener); + + result = listener_startclients(listener); + if (result != ISC_R_SUCCESS) { + isc_sockaddr_format(address, socktext, sizeof(socktext)); + isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL, + NS_LOGMODULE_LWRESD, ISC_LOG_WARNING, + "lwres: failed to start %s: %s", socktext, + isc_result_totext(result)); + ns_lwreslistener_detach(&listener); + return (ISC_R_SUCCESS); + } + + if (oldlistener != NULL) { + /* + * Remove the old listener from the old list and shut it down. + */ + ISC_LIST_UNLINK(listeners, oldlistener, link); + listener_shutdown(oldlistener); + ns_lwreslistener_detach(&oldlistener); + } else { + isc_sockaddr_format(address, socktext, sizeof(socktext)); + isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL, + NS_LOGMODULE_LWRESD, ISC_LOG_NOTICE, + "lwres listening on %s", socktext); + } + + ISC_LIST_APPEND(*newlisteners, listener, link); + return (result); +} + +isc_result_t +ns_lwresd_configure(isc_mem_t *mctx, const cfg_obj_t *config) { + const cfg_obj_t *lwreslist = NULL; + const cfg_obj_t *lwres = NULL; + const cfg_obj_t *listenerslist = NULL; + const cfg_listelt_t *element = NULL; + ns_lwreslistener_t *listener; + ns_lwreslistenerlist_t newlisteners; + isc_result_t result; + char socktext[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_t *addrs = NULL; + ns_lwresd_t *lwresd = NULL; + isc_uint32_t count = 0; + + REQUIRE(mctx != NULL); + REQUIRE(config != NULL); + + RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS); + + ISC_LIST_INIT(newlisteners); + + result = cfg_map_get(config, "lwres", &lwreslist); + if (result != ISC_R_SUCCESS) + return (ISC_R_SUCCESS); + + LOCK(&listeners_lock); + /* + * Run through the new lwres address list, noting sockets that + * are already being listened on and moving them to the new list. + * + * Identifying duplicates addr/port combinations is left to either + * the underlying config code, or to the bind attempt getting an + * address-in-use error. + */ + for (element = cfg_list_first(lwreslist); + element != NULL; + element = cfg_list_next(element)) + { + in_port_t port; + + lwres = cfg_listelt_value(element); + CHECK(ns_lwdmanager_create(mctx, lwres, &lwresd)); + + port = lwresd_g_listenport; + if (port == 0) + port = LWRES_UDP_PORT; + + listenerslist = NULL; + (void)cfg_map_get(lwres, "listen-on", &listenerslist); + if (listenerslist == NULL) { + struct in_addr localhost; + isc_sockaddr_t address; + + localhost.s_addr = htonl(INADDR_LOOPBACK); + isc_sockaddr_fromin(&address, &localhost, port); + CHECK(configure_listener(&address, lwresd, mctx, + &newlisteners)); + } else { + isc_uint32_t i; + + CHECK(ns_config_getiplist(config, listenerslist, + port, mctx, &addrs, &count)); + for (i = 0; i < count; i++) + CHECK(configure_listener(&addrs[i], lwresd, + mctx, &newlisteners)); + ns_config_putiplist(mctx, &addrs, count); + } + ns_lwdmanager_detach(&lwresd); + } + + /* + * Shutdown everything on the listeners list, and remove them from + * the list. Then put all of the new listeners on it. + */ + + while (!ISC_LIST_EMPTY(listeners)) { + listener = ISC_LIST_HEAD(listeners); + ISC_LIST_UNLINK(listeners, listener, link); + + isc_sockaddr_format(&listener->address, + socktext, sizeof(socktext)); + + listener_shutdown(listener); + ns_lwreslistener_detach(&listener); + + isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL, + NS_LOGMODULE_LWRESD, ISC_LOG_NOTICE, + "lwres no longer listening on %s", socktext); + } + + cleanup: + ISC_LIST_APPENDLIST(listeners, newlisteners, link); + + if (addrs != NULL) + ns_config_putiplist(mctx, &addrs, count); + + if (lwresd != NULL) + ns_lwdmanager_detach(&lwresd); + + UNLOCK(&listeners_lock); + + return (result); +} + +void +ns_lwresd_shutdown(void) { + ns_lwreslistener_t *listener; + + RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS); + + while (!ISC_LIST_EMPTY(listeners)) { + listener = ISC_LIST_HEAD(listeners); + ISC_LIST_UNLINK(listeners, listener, link); + ns_lwreslistener_detach(&listener); + } +} diff --git a/contrib/bind-9.5.2/bin/named/lwresd.html b/contrib/bind-9.5.2/bin/named/lwresd.html new file mode 100644 index 0000000000..d5e060dd17 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/lwresd.html @@ -0,0 +1,225 @@ + + + + + +lwresd + + +
+
+
+

Name

+

lwresd — lightweight resolver daemon

+
+
+

Synopsis

+

lwresd [-c config-file] [-C config-file] [-d debug-level] [-f] [-g] [-i pid-file] [-m flag] [-n #cpus] [-P port] [-p port] [-s] [-t directory] [-u user] [-v] [-4] [-6]

+
+
+

DESCRIPTION

+

lwresd + is the daemon providing name lookup + services to clients that use the BIND 9 lightweight resolver + library. It is essentially a stripped-down, caching-only name + server that answers queries using the BIND 9 lightweight + resolver protocol rather than the DNS protocol. +

+

lwresd + listens for resolver queries on a + UDP port on the IPv4 loopback interface, 127.0.0.1. This + means that lwresd can only be used by + processes running on the local machine. By default, UDP port + number 921 is used for lightweight resolver requests and + responses. +

+

+ Incoming lightweight resolver requests are decoded by the + server which then resolves them using the DNS protocol. When + the DNS lookup completes, lwresd encodes + the answers in the lightweight resolver format and returns + them to the client that made the request. +

+

+ If /etc/resolv.conf contains any + nameserver entries, lwresd + sends recursive DNS queries to those servers. This is similar + to the use of forwarders in a caching name server. If no + nameserver entries are present, or if + forwarding fails, lwresd resolves the + queries autonomously starting at the root name servers, using + a built-in list of root server hints. +

+
+
+

OPTIONS

+
+
-4
+

+ Use IPv4 only even if the host machine is capable of IPv6. + -4 and -6 are mutually + exclusive. +

+
-6
+

+ Use IPv6 only even if the host machine is capable of IPv4. + -4 and -6 are mutually + exclusive. +

+
-c config-file
+

+ Use config-file as the + configuration file instead of the default, + /etc/lwresd.conf. + + -c can not be used with -C. +

+
-C config-file
+

+ Use config-file as the + configuration file instead of the default, + /etc/resolv.conf. + -C can not be used with -c. +

+
-d debug-level
+

+ Set the daemon's debug level to debug-level. + Debugging traces from lwresd become + more verbose as the debug level increases. +

+
-f
+

+ Run the server in the foreground (i.e. do not daemonize). +

+
-g
+

+ Run the server in the foreground and force all logging + to stderr. +

+
-i pid-file
+

+ Use pid-file as the + PID file instead of the default, + /var/run/lwresd.pid. +

+
-m flag
+

+ Turn on memory usage debugging flags. Possible flags are + usage, + trace, + record, + size, and + mctx. + These correspond to the ISC_MEM_DEBUGXXXX flags described in + <isc/mem.h>. +

+
-n #cpus
+

+ Create #cpus worker threads + to take advantage of multiple CPUs. If not specified, + lwresd will try to determine the + number of CPUs present and create one thread per CPU. + If it is unable to determine the number of CPUs, a + single worker thread will be created. +

+
-P port
+

+ Listen for lightweight resolver queries on port + port. If + not specified, the default is port 921. +

+
-p port
+

+ Send DNS lookups to port port. If not + specified, the default is port 53. This provides a + way of testing the lightweight resolver daemon with a + name server that listens for queries on a non-standard + port number. +

+
-s
+
+

+ Write memory usage statistics to stdout + on exit. +

+
+

Note

+

+ This option is mainly of interest to BIND 9 developers + and may be removed or changed in a future release. +

+
+
+
-t directory
+
+

Chroot + to directory after + processing the command line arguments, but before + reading the configuration file. +

+
+

Warning

+

+ This option should be used in conjunction with the + -u option, as chrooting a process + running as root doesn't enhance security on most + systems; the way chroot(2) is + defined allows a process with root privileges to + escape a chroot jail. +

+
+
+
-u user
+

Setuid + to user after completing + privileged operations, such as creating sockets that + listen on privileged ports. +

+
-v
+

+ Report the version number and exit. +

+
+
+
+

FILES

+
+
/etc/resolv.conf
+

+ The default configuration file. +

+
/var/run/lwresd.pid
+

+ The default process-id file. +

+
+
+
+

SEE ALSO

+

named(8), + lwres(3), + resolver(5). +

+
+
+

AUTHOR

+

Internet Systems Consortium +

+
+
+ diff --git a/contrib/bind-9.5.2/bin/named/lwsearch.c b/contrib/bind-9.5.2/bin/named/lwsearch.c new file mode 100644 index 0000000000..6754c987bc --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/lwsearch.c @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * 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: lwsearch.c,v 1.13 2007/06/19 23:46:59 tbox Exp $ */ + +/*! \file */ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#define LWSEARCHLIST_MAGIC ISC_MAGIC('L', 'W', 'S', 'L') +#define VALID_LWSEARCHLIST(l) ISC_MAGIC_VALID(l, LWSEARCHLIST_MAGIC) + +isc_result_t +ns_lwsearchlist_create(isc_mem_t *mctx, ns_lwsearchlist_t **listp) { + ns_lwsearchlist_t *list; + isc_result_t result; + + REQUIRE(mctx != NULL); + REQUIRE(listp != NULL && *listp == NULL); + + list = isc_mem_get(mctx, sizeof(ns_lwsearchlist_t)); + if (list == NULL) + return (ISC_R_NOMEMORY); + + result = isc_mutex_init(&list->lock); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, list, sizeof(ns_lwsearchlist_t)); + return (result); + } + list->mctx = NULL; + isc_mem_attach(mctx, &list->mctx); + list->refs = 1; + ISC_LIST_INIT(list->names); + list->magic = LWSEARCHLIST_MAGIC; + + *listp = list; + return (ISC_R_SUCCESS); +} + +void +ns_lwsearchlist_attach(ns_lwsearchlist_t *source, ns_lwsearchlist_t **target) { + REQUIRE(VALID_LWSEARCHLIST(source)); + REQUIRE(target != NULL && *target == NULL); + + LOCK(&source->lock); + INSIST(source->refs > 0); + source->refs++; + INSIST(source->refs != 0); + UNLOCK(&source->lock); + + *target = source; +} + +void +ns_lwsearchlist_detach(ns_lwsearchlist_t **listp) { + ns_lwsearchlist_t *list; + isc_mem_t *mctx; + + REQUIRE(listp != NULL); + list = *listp; + REQUIRE(VALID_LWSEARCHLIST(list)); + + LOCK(&list->lock); + INSIST(list->refs > 0); + list->refs--; + UNLOCK(&list->lock); + + *listp = NULL; + if (list->refs != 0) + return; + + mctx = list->mctx; + while (!ISC_LIST_EMPTY(list->names)) { + dns_name_t *name = ISC_LIST_HEAD(list->names); + ISC_LIST_UNLINK(list->names, name, link); + dns_name_free(name, list->mctx); + isc_mem_put(list->mctx, name, sizeof(dns_name_t)); + } + list->magic = 0; + isc_mem_put(mctx, list, sizeof(ns_lwsearchlist_t)); + isc_mem_detach(&mctx); +} + +isc_result_t +ns_lwsearchlist_append(ns_lwsearchlist_t *list, dns_name_t *name) { + dns_name_t *newname; + isc_result_t result; + + REQUIRE(VALID_LWSEARCHLIST(list)); + REQUIRE(name != NULL); + + newname = isc_mem_get(list->mctx, sizeof(dns_name_t)); + if (newname == NULL) + return (ISC_R_NOMEMORY); + dns_name_init(newname, NULL); + result = dns_name_dup(name, list->mctx, newname); + if (result != ISC_R_SUCCESS) { + isc_mem_put(list->mctx, newname, sizeof(dns_name_t)); + return (result); + } + ISC_LINK_INIT(newname, link); + ISC_LIST_APPEND(list->names, newname, link); + return (ISC_R_SUCCESS); +} + +void +ns_lwsearchctx_init(ns_lwsearchctx_t *sctx, ns_lwsearchlist_t *list, + dns_name_t *name, unsigned int ndots) +{ + INSIST(sctx != NULL); + sctx->relname = name; + sctx->searchname = NULL; + sctx->doneexact = ISC_FALSE; + sctx->exactfirst = ISC_FALSE; + sctx->ndots = ndots; + if (dns_name_isabsolute(name) || list == NULL) { + sctx->list = NULL; + return; + } + sctx->list = list; + sctx->searchname = ISC_LIST_HEAD(sctx->list->names); + if (dns_name_countlabels(name) > ndots) + sctx->exactfirst = ISC_TRUE; +} + +void +ns_lwsearchctx_first(ns_lwsearchctx_t *sctx) { + REQUIRE(sctx != NULL); + UNUSED(sctx); +} + +isc_result_t +ns_lwsearchctx_next(ns_lwsearchctx_t *sctx) { + REQUIRE(sctx != NULL); + + if (sctx->list == NULL) + return (ISC_R_NOMORE); + + if (sctx->searchname == NULL) { + INSIST (!sctx->exactfirst || sctx->doneexact); + if (sctx->exactfirst || sctx->doneexact) + return (ISC_R_NOMORE); + sctx->doneexact = ISC_TRUE; + } else { + if (sctx->exactfirst && !sctx->doneexact) + sctx->doneexact = ISC_TRUE; + else { + sctx->searchname = ISC_LIST_NEXT(sctx->searchname, + link); + if (sctx->searchname == NULL && sctx->doneexact) + return (ISC_R_NOMORE); + } + } + + return (ISC_R_SUCCESS); +} + +isc_result_t +ns_lwsearchctx_current(ns_lwsearchctx_t *sctx, dns_name_t *absname) { + dns_name_t *tname; + isc_boolean_t useexact = ISC_FALSE; + + REQUIRE(sctx != NULL); + + if (sctx->list == NULL || + sctx->searchname == NULL || + (sctx->exactfirst && !sctx->doneexact)) + useexact = ISC_TRUE; + + if (useexact) { + if (dns_name_isabsolute(sctx->relname)) + tname = NULL; + else + tname = dns_rootname; + } else + tname = sctx->searchname; + + return (dns_name_concatenate(sctx->relname, tname, absname, NULL)); +} diff --git a/contrib/bind-9.5.2/bin/named/main.c b/contrib/bind-9.5.2/bin/named/main.c new file mode 100644 index 0000000000..6892fc7df0 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/main.c @@ -0,0 +1,973 @@ +/* + * Copyright (C) 2004-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 + * 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: main.c,v 1.158.48.8 2009/04/03 20:18:26 marka Exp $ */ + +/*! \file */ + +#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 + +/* + * Defining NS_MAIN provides storage declarations (rather than extern) + * for variables in named/globals.h. + */ +#define NS_MAIN 1 + +#include +#include +#include /* Explicit, though named/log.h includes it. */ +#include +#include +#include +#include +#include +#include +#ifdef HAVE_LIBSCF +#include +#endif + +/* + * Include header files for database drivers here. + */ +/* #include "xxdb.h" */ + +/* + * Include DLZ drivers if appropriate. + */ +#ifdef DLZ +#include +#endif + +static isc_boolean_t want_stats = ISC_FALSE; +static char program_name[ISC_DIR_NAMEMAX] = "named"; +static char absolute_conffile[ISC_DIR_PATHMAX]; +static char saved_command_line[512]; +static char version[512]; +static unsigned int maxsocks = 0; + +void +ns_main_earlywarning(const char *format, ...) { + va_list args; + + va_start(args, format); + if (ns_g_lctx != NULL) { + isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_MAIN, ISC_LOG_WARNING, + format, args); + } else { + fprintf(stderr, "%s: ", program_name); + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); + fflush(stderr); + } + va_end(args); +} + +void +ns_main_earlyfatal(const char *format, ...) { + va_list args; + + va_start(args, format); + if (ns_g_lctx != NULL) { + isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL, + format, args); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL, + "exiting (due to early fatal error)"); + } else { + fprintf(stderr, "%s: ", program_name); + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); + fflush(stderr); + } + va_end(args); + + exit(1); +} + +static void +assertion_failed(const char *file, int line, isc_assertiontype_t type, + const char *cond) +{ + /* + * Handle assertion failures. + */ + + if (ns_g_lctx != NULL) { + /* + * Reset the assertion callback in case it is the log + * routines causing the assertion. + */ + isc_assertion_setcallback(NULL); + + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL, + "%s:%d: %s(%s) failed", file, line, + isc_assertion_typetotext(type), cond); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL, + "exiting (due to assertion failure)"); + } else { + fprintf(stderr, "%s:%d: %s(%s) failed\n", + file, line, isc_assertion_typetotext(type), cond); + fflush(stderr); + } + + if (ns_g_coreok) + abort(); + exit(1); +} + +static void +library_fatal_error(const char *file, int line, const char *format, + va_list args) ISC_FORMAT_PRINTF(3, 0); + +static void +library_fatal_error(const char *file, int line, const char *format, + va_list args) +{ + /* + * Handle isc_error_fatal() calls from our libraries. + */ + + if (ns_g_lctx != NULL) { + /* + * Reset the error callback in case it is the log + * routines causing the assertion. + */ + isc_error_setfatal(NULL); + + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL, + "%s:%d: fatal error:", file, line); + isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL, + format, args); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL, + "exiting (due to fatal error in library)"); + } else { + fprintf(stderr, "%s:%d: fatal error: ", file, line); + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); + fflush(stderr); + } + + if (ns_g_coreok) + abort(); + exit(1); +} + +static void +library_unexpected_error(const char *file, int line, const char *format, + va_list args) ISC_FORMAT_PRINTF(3, 0); + +static void +library_unexpected_error(const char *file, int line, const char *format, + va_list args) +{ + /* + * Handle isc_error_unexpected() calls from our libraries. + */ + + if (ns_g_lctx != NULL) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_MAIN, ISC_LOG_ERROR, + "%s:%d: unexpected error:", file, line); + isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_MAIN, ISC_LOG_ERROR, + format, args); + } else { + fprintf(stderr, "%s:%d: fatal error: ", file, line); + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); + fflush(stderr); + } +} + +static void +lwresd_usage(void) { + fprintf(stderr, + "usage: lwresd [-4|-6] [-c conffile | -C resolvconffile] " + "[-d debuglevel]\n" + " [-f|-g] [-n number_of_cpus] [-p port] " + "[-P listen-port] [-s]\n" + " [-t chrootdir] [-u username] [-i pidfile]\n" + " [-m {usage|trace|record|size|mctx}]\n"); +} + +static void +usage(void) { + if (ns_g_lwresdonly) { + lwresd_usage(); + return; + } + fprintf(stderr, + "usage: named [-4|-6] [-c conffile] [-d debuglevel] " + "[-f|-g] [-n number_of_cpus]\n" + " [-p port] [-s] [-t chrootdir] [-u username]\n" + " [-m {usage|trace|record|size|mctx}]\n"); +} + +static void +save_command_line(int argc, char *argv[]) { + int i; + char *src; + char *dst; + char *eob; + const char truncated[] = "..."; + isc_boolean_t quoted = ISC_FALSE; + + dst = saved_command_line; + eob = saved_command_line + sizeof(saved_command_line); + + for (i = 1; i < argc && dst < eob; i++) { + *dst++ = ' '; + + src = argv[i]; + while (*src != '\0' && dst < eob) { + /* + * This won't perfectly produce a shell-independent + * pastable command line in all circumstances, but + * comes close, and for practical purposes will + * nearly always be fine. + */ + if (quoted || isalnum(*src & 0xff) || + *src == '-' || *src == '_' || + *src == '.' || *src == '/') { + *dst++ = *src++; + quoted = ISC_FALSE; + } else { + *dst++ = '\\'; + quoted = ISC_TRUE; + } + } + } + + INSIST(sizeof(saved_command_line) >= sizeof(truncated)); + + if (dst == eob) + strcpy(eob - sizeof(truncated), truncated); + else + *dst = '\0'; +} + +static int +parse_int(char *arg, const char *desc) { + char *endp; + int tmp; + long int ltmp; + + ltmp = strtol(arg, &endp, 10); + tmp = (int) ltmp; + if (*endp != '\0') + ns_main_earlyfatal("%s '%s' must be numeric", desc, arg); + if (tmp < 0 || tmp != ltmp) + ns_main_earlyfatal("%s '%s' out of range", desc, arg); + return (tmp); +} + +static struct flag_def { + const char *name; + unsigned int value; +} mem_debug_flags[] = { + { "trace", ISC_MEM_DEBUGTRACE }, + { "record", ISC_MEM_DEBUGRECORD }, + { "usage", ISC_MEM_DEBUGUSAGE }, + { "size", ISC_MEM_DEBUGSIZE }, + { "mctx", ISC_MEM_DEBUGCTX }, + { NULL, 0 } +}; + +static void +set_flags(const char *arg, struct flag_def *defs, unsigned int *ret) { + for (;;) { + const struct flag_def *def; + const char *end = strchr(arg, ','); + int arglen; + if (end == NULL) + end = arg + strlen(arg); + arglen = end - arg; + for (def = defs; def->name != NULL; def++) { + if (arglen == (int)strlen(def->name) && + memcmp(arg, def->name, arglen) == 0) { + *ret |= def->value; + goto found; + } + } + ns_main_earlyfatal("unrecognized flag '%.*s'", arglen, arg); + found: + if (*end == '\0') + break; + arg = end + 1; + } +} + +static void +parse_command_line(int argc, char *argv[]) { + int ch; + int port; + isc_boolean_t disable6 = ISC_FALSE; + isc_boolean_t disable4 = ISC_FALSE; + + save_command_line(argc, argv); + + isc_commandline_errprint = ISC_FALSE; + while ((ch = isc_commandline_parse(argc, argv, + "46c:C:d:fgi:lm:n:N:p:P:" + "sS:t:u:vx:")) != -1) { + switch (ch) { + case '4': + if (disable4) + ns_main_earlyfatal("cannot specify -4 and -6"); + if (isc_net_probeipv4() != ISC_R_SUCCESS) + ns_main_earlyfatal("IPv4 not supported by OS"); + isc_net_disableipv6(); + disable6 = ISC_TRUE; + break; + case '6': + if (disable6) + ns_main_earlyfatal("cannot specify -4 and -6"); + if (isc_net_probeipv6() != ISC_R_SUCCESS) + ns_main_earlyfatal("IPv6 not supported by OS"); + isc_net_disableipv4(); + disable4 = ISC_TRUE; + break; + case 'c': + ns_g_conffile = isc_commandline_argument; + lwresd_g_conffile = isc_commandline_argument; + if (lwresd_g_useresolvconf) + ns_main_earlyfatal("cannot specify -c and -C"); + ns_g_conffileset = ISC_TRUE; + break; + case 'C': + lwresd_g_resolvconffile = isc_commandline_argument; + if (ns_g_conffileset) + ns_main_earlyfatal("cannot specify -c and -C"); + lwresd_g_useresolvconf = ISC_TRUE; + break; + case 'd': + ns_g_debuglevel = parse_int(isc_commandline_argument, + "debug level"); + break; + case 'f': + ns_g_foreground = ISC_TRUE; + break; + case 'g': + ns_g_foreground = ISC_TRUE; + ns_g_logstderr = ISC_TRUE; + break; + /* XXXBEW -i should be removed */ + case 'i': + lwresd_g_defaultpidfile = isc_commandline_argument; + break; + case 'l': + ns_g_lwresdonly = ISC_TRUE; + break; + case 'm': + set_flags(isc_commandline_argument, mem_debug_flags, + &isc_mem_debugging); + break; + case 'N': /* Deprecated. */ + case 'n': + ns_g_cpus = parse_int(isc_commandline_argument, + "number of cpus"); + if (ns_g_cpus == 0) + ns_g_cpus = 1; + break; + case 'p': + port = parse_int(isc_commandline_argument, "port"); + if (port < 1 || port > 65535) + ns_main_earlyfatal("port '%s' out of range", + isc_commandline_argument); + ns_g_port = port; + break; + /* XXXBEW Should -P be removed? */ + case 'P': + port = parse_int(isc_commandline_argument, "port"); + if (port < 1 || port > 65535) + ns_main_earlyfatal("port '%s' out of range", + isc_commandline_argument); + lwresd_g_listenport = port; + break; + case 's': + /* XXXRTH temporary syntax */ + want_stats = ISC_TRUE; + break; + case 'S': + maxsocks = parse_int(isc_commandline_argument, + "max number of sockets"); + break; + case 't': + /* XXXJAB should we make a copy? */ + ns_g_chrootdir = isc_commandline_argument; + break; + case 'u': + ns_g_username = isc_commandline_argument; + break; + case 'v': + printf("BIND %s\n", ns_g_version); + exit(0); + case '?': + usage(); + if (isc_commandline_option == '?') + exit(0); + ns_main_earlyfatal("unknown option '-%c'", + isc_commandline_option); + default: + ns_main_earlyfatal("parsing options returned %d", ch); + } + } + + argc -= isc_commandline_index; + argv += isc_commandline_index; + + if (argc > 0) { + usage(); + ns_main_earlyfatal("extra command line arguments"); + } +} + +static isc_result_t +create_managers(void) { + isc_result_t result; + unsigned int socks; + +#ifdef ISC_PLATFORM_USETHREADS + if (ns_g_cpus == 0) + ns_g_cpus = ns_g_cpus_detected; + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, + ISC_LOG_INFO, "found %u CPU%s, using %u worker thread%s", + ns_g_cpus_detected, ns_g_cpus_detected == 1 ? "" : "s", + ns_g_cpus, ns_g_cpus == 1 ? "" : "s"); +#else + ns_g_cpus = 1; +#endif + result = isc_taskmgr_create(ns_g_mctx, ns_g_cpus, 0, &ns_g_taskmgr); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_taskmgr_create() failed: %s", + isc_result_totext(result)); + return (ISC_R_UNEXPECTED); + } + + result = isc_timermgr_create(ns_g_mctx, &ns_g_timermgr); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_timermgr_create() failed: %s", + isc_result_totext(result)); + return (ISC_R_UNEXPECTED); + } + + result = isc_socketmgr_create2(ns_g_mctx, &ns_g_socketmgr, maxsocks); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_socketmgr_create() failed: %s", + isc_result_totext(result)); + return (ISC_R_UNEXPECTED); + } + result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &socks); + if (result == ISC_R_SUCCESS) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, + ISC_LOG_INFO, "using up to %u sockets", socks); + } + + result = isc_entropy_create(ns_g_mctx, &ns_g_entropy); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_entropy_create() failed: %s", + isc_result_totext(result)); + return (ISC_R_UNEXPECTED); + } + + result = isc_hash_create(ns_g_mctx, ns_g_entropy, DNS_NAME_MAXWIRE); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_hash_create() failed: %s", + isc_result_totext(result)); + return (ISC_R_UNEXPECTED); + } + + return (ISC_R_SUCCESS); +} + +static void +destroy_managers(void) { + ns_lwresd_shutdown(); + + isc_entropy_detach(&ns_g_entropy); + if (ns_g_fallbackentropy != NULL) + isc_entropy_detach(&ns_g_fallbackentropy); + + /* + * isc_taskmgr_destroy() will block until all tasks have exited, + */ + isc_taskmgr_destroy(&ns_g_taskmgr); + isc_timermgr_destroy(&ns_g_timermgr); + isc_socketmgr_destroy(&ns_g_socketmgr); + + /* + * isc_hash_destroy() cannot be called as long as a resolver may be + * running. Calling this after isc_taskmgr_destroy() ensures the + * call is safe. + */ + isc_hash_destroy(); +} + +static void +setup(void) { + isc_result_t result; + isc_resourcevalue_t old_openfiles; +#ifdef HAVE_LIBSCF + char *instance = NULL; +#endif + + /* + * Get the user and group information before changing the root + * directory, so the administrator does not need to keep a copy + * of the user and group databases in the chroot'ed environment. + */ + ns_os_inituserinfo(ns_g_username); + + /* + * Initialize time conversion information + */ + ns_os_tzset(); + + ns_os_opendevnull(); + +#ifdef HAVE_LIBSCF + /* Check if named is under smf control, before chroot. */ + result = ns_smf_get_instance(&instance, 0, ns_g_mctx); + /* We don't care about instance, just check if we got one. */ + if (result == ISC_R_SUCCESS) + ns_smf_got_instance = 1; + else + ns_smf_got_instance = 0; + if (instance != NULL) + isc_mem_free(ns_g_mctx, instance); +#endif /* HAVE_LIBSCF */ + +#ifdef PATH_RANDOMDEV + /* + * Initialize system's random device as fallback entropy source + * if running chroot'ed. + */ + if (ns_g_chrootdir != NULL) { + result = isc_entropy_create(ns_g_mctx, &ns_g_fallbackentropy); + if (result != ISC_R_SUCCESS) + ns_main_earlyfatal("isc_entropy_create() failed: %s", + isc_result_totext(result)); + + result = isc_entropy_createfilesource(ns_g_fallbackentropy, + PATH_RANDOMDEV); + if (result != ISC_R_SUCCESS) { + ns_main_earlywarning("could not open pre-chroot " + "entropy source %s: %s", + PATH_RANDOMDEV, + isc_result_totext(result)); + isc_entropy_detach(&ns_g_fallbackentropy); + } + } +#endif + +#ifdef ISC_PLATFORM_USETHREADS + /* + * Check for the number of cpu's before ns_os_chroot(). + */ + ns_g_cpus_detected = isc_os_ncpus(); +#endif + + ns_os_chroot(ns_g_chrootdir); + + /* + * For operating systems which have a capability mechanism, now + * is the time to switch to minimal privs and change our user id. + * On traditional UNIX systems, this call will be a no-op, and we + * will change the user ID after reading the config file the first + * time. (We need to read the config file to know which possibly + * privileged ports to bind() to.) + */ + ns_os_minprivs(); + + result = ns_log_init(ISC_TF(ns_g_username != NULL)); + if (result != ISC_R_SUCCESS) + ns_main_earlyfatal("ns_log_init() failed: %s", + isc_result_totext(result)); + + /* + * Now is the time to daemonize (if we're not running in the + * foreground). We waited until now because we wanted to get + * a valid logging context setup. We cannot daemonize any later, + * because calling create_managers() will create threads, which + * would be lost after fork(). + */ + if (!ns_g_foreground) + ns_os_daemonize(); + + /* + * We call isc_app_start() here as some versions of FreeBSD's fork() + * destroys all the signal handling it sets up. + */ + result = isc_app_start(); + if (result != ISC_R_SUCCESS) + ns_main_earlyfatal("isc_app_start() failed: %s", + isc_result_totext(result)); + + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, + ISC_LOG_NOTICE, "starting BIND %s%s", ns_g_version, + saved_command_line); + + /* + * Get the initial resource limits. + */ + (void)isc_resource_getlimit(isc_resource_stacksize, + &ns_g_initstacksize); + (void)isc_resource_getlimit(isc_resource_datasize, + &ns_g_initdatasize); + (void)isc_resource_getlimit(isc_resource_coresize, + &ns_g_initcoresize); + (void)isc_resource_getlimit(isc_resource_openfiles, + &ns_g_initopenfiles); + + /* + * System resources cannot effectively be tuned on some systems. + * Raise the limit in such cases for safety. + */ + old_openfiles = ns_g_initopenfiles; + ns_os_adjustnofile(); + (void)isc_resource_getlimit(isc_resource_openfiles, + &ns_g_initopenfiles); + if (old_openfiles != ns_g_initopenfiles) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "adjusted limit on open files from " + "%" ISC_PRINT_QUADFORMAT "u to " + "%" ISC_PRINT_QUADFORMAT "u", + old_openfiles, ns_g_initopenfiles); + } + + /* + * If the named configuration filename is relative, prepend the current + * directory's name before possibly changing to another directory. + */ + if (! isc_file_isabsolute(ns_g_conffile)) { + result = isc_file_absolutepath(ns_g_conffile, + absolute_conffile, + sizeof(absolute_conffile)); + if (result != ISC_R_SUCCESS) + ns_main_earlyfatal("could not construct absolute path of " + "configuration file: %s", + isc_result_totext(result)); + ns_g_conffile = absolute_conffile; + } + + /* + * Record the server's startup time. + */ + result = isc_time_now(&ns_g_boottime); + if (result != ISC_R_SUCCESS) + ns_main_earlyfatal("isc_time_now() failed: %s", + isc_result_totext(result)); + + result = create_managers(); + if (result != ISC_R_SUCCESS) + ns_main_earlyfatal("create_managers() failed: %s", + isc_result_totext(result)); + + ns_builtin_init(); + + /* + * Add calls to register sdb drivers here. + */ + /* xxdb_init(); */ + +#ifdef DLZ + /* + * Register any DLZ drivers. + */ + result = dlz_drivers_init(); + if (result != ISC_R_SUCCESS) + ns_main_earlyfatal("dlz_drivers_init() failed: %s", + isc_result_totext(result)); +#endif + + ns_server_create(ns_g_mctx, &ns_g_server); +} + +static void +cleanup(void) { + destroy_managers(); + + ns_server_destroy(&ns_g_server); + + ns_builtin_deinit(); + + /* + * Add calls to unregister sdb drivers here. + */ + /* xxdb_clear(); */ + +#ifdef DLZ + /* + * Unregister any DLZ drivers. + */ + dlz_drivers_clear(); +#endif + + dns_name_destroy(); + + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, + ISC_LOG_NOTICE, "exiting"); + ns_log_shutdown(); +} + +static char *memstats = NULL; + +void +ns_main_setmemstats(const char *filename) { + /* + * Caller has to ensure locking. + */ + + if (memstats != NULL) { + free(memstats); + memstats = NULL; + } + if (filename == NULL) + return; + memstats = malloc(strlen(filename) + 1); + if (memstats) + strcpy(memstats, filename); +} + +#ifdef HAVE_LIBSCF +/* + * Get FMRI for the named process. + */ +isc_result_t +ns_smf_get_instance(char **ins_name, int debug, isc_mem_t *mctx) { + scf_handle_t *h = NULL; + int namelen; + char *instance; + + REQUIRE(ins_name != NULL && *ins_name == NULL); + + if ((h = scf_handle_create(SCF_VERSION)) == NULL) { + if (debug) + UNEXPECTED_ERROR(__FILE__, __LINE__, + "scf_handle_create() failed: %s", + scf_strerror(scf_error())); + return (ISC_R_FAILURE); + } + + if (scf_handle_bind(h) == -1) { + if (debug) + UNEXPECTED_ERROR(__FILE__, __LINE__, + "scf_handle_bind() failed: %s", + scf_strerror(scf_error())); + scf_handle_destroy(h); + return (ISC_R_FAILURE); + } + + if ((namelen = scf_myname(h, NULL, 0)) == -1) { + if (debug) + UNEXPECTED_ERROR(__FILE__, __LINE__, + "scf_myname() failed: %s", + scf_strerror(scf_error())); + scf_handle_destroy(h); + return (ISC_R_FAILURE); + } + + if ((instance = isc_mem_allocate(mctx, namelen + 1)) == NULL) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "ns_smf_get_instance memory " + "allocation failed: %s", + isc_result_totext(ISC_R_NOMEMORY)); + scf_handle_destroy(h); + return (ISC_R_FAILURE); + } + + if (scf_myname(h, instance, namelen + 1) == -1) { + if (debug) + UNEXPECTED_ERROR(__FILE__, __LINE__, + "scf_myname() failed: %s", + scf_strerror(scf_error())); + scf_handle_destroy(h); + isc_mem_free(mctx, instance); + return (ISC_R_FAILURE); + } + + scf_handle_destroy(h); + *ins_name = instance; + return (ISC_R_SUCCESS); +} +#endif /* HAVE_LIBSCF */ + +int +main(int argc, char *argv[]) { + isc_result_t result; +#ifdef HAVE_LIBSCF + char *instance = NULL; +#endif + + /* + * Record version in core image. + * strings named.core | grep "named version:" + */ + strlcat(version, +#if defined(NO_VERSION_DATE) || !defined(__DATE__) + "named version: BIND " VERSION, +#else + "named version: BIND " VERSION " (" __DATE__ ")", +#endif + sizeof(version)); + result = isc_file_progname(*argv, program_name, sizeof(program_name)); + if (result != ISC_R_SUCCESS) + ns_main_earlyfatal("program name too long"); + + if (strcmp(program_name, "lwresd") == 0) + ns_g_lwresdonly = ISC_TRUE; + + isc_assertion_setcallback(assertion_failed); + isc_error_setfatal(library_fatal_error); + isc_error_setunexpected(library_unexpected_error); + + ns_os_init(program_name); + + dns_result_register(); + dst_result_register(); + isccc_result_register(); + + parse_command_line(argc, argv); + + /* + * Warn about common configuration error. + */ + if (ns_g_chrootdir != NULL) { + int len = strlen(ns_g_chrootdir); + if (strncmp(ns_g_chrootdir, ns_g_conffile, len) == 0 && + (ns_g_conffile[len] == '/' || ns_g_conffile[len] == '\\')) + ns_main_earlywarning("config filename (-c %s) contains " + "chroot path (-t %s)", + ns_g_conffile, ns_g_chrootdir); + } + + result = isc_mem_create(0, 0, &ns_g_mctx); + if (result != ISC_R_SUCCESS) + ns_main_earlyfatal("isc_mem_create() failed: %s", + isc_result_totext(result)); + isc_mem_setname(ns_g_mctx, "main", NULL); + + setup(); + + /* + * Start things running and then wait for a shutdown request + * or reload. + */ + do { + result = isc_app_run(); + + if (result == ISC_R_RELOAD) { + ns_server_reloadwanted(ns_g_server); + } else if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_run(): %s", + isc_result_totext(result)); + /* + * Force exit. + */ + result = ISC_R_SUCCESS; + } + } while (result != ISC_R_SUCCESS); + +#ifdef HAVE_LIBSCF + if (ns_smf_want_disable == 1) { + result = ns_smf_get_instance(&instance, 1, ns_g_mctx); + if (result == ISC_R_SUCCESS && instance != NULL) { + if (smf_disable_instance(instance, 0) != 0) + UNEXPECTED_ERROR(__FILE__, __LINE__, + "smf_disable_instance() " + "failed for %s : %s", + instance, + scf_strerror(scf_error())); + } + if (instance != NULL) + isc_mem_free(ns_g_mctx, instance); + } +#endif /* HAVE_LIBSCF */ + + cleanup(); + + if (want_stats) { + isc_mem_stats(ns_g_mctx, stdout); + isc_mutex_stats(stdout); + } + + if (ns_g_memstatistics && memstats != NULL) { + FILE *fp = NULL; + result = isc_stdio_open(memstats, "w", &fp); + if (result == ISC_R_SUCCESS) { + isc_mem_stats(ns_g_mctx, fp); + isc_mutex_stats(fp); + isc_stdio_close(fp); + } + } + isc_mem_destroy(&ns_g_mctx); + isc_mem_checkdestroyed(stderr); + + ns_main_setmemstats(NULL); + + isc_app_finish(); + + ns_os_closedevnull(); + + ns_os_shutdown(); + + return (0); +} diff --git a/contrib/bind-9.5.2/bin/named/named.8 b/contrib/bind-9.5.2/bin/named/named.8 new file mode 100644 index 0000000000..bf22aa34a8 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/named.8 @@ -0,0 +1,251 @@ +.\" Copyright (C) 2004-2008 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 +.\" 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: named.8,v 1.34.130.2 2009/07/11 01:43:29 tbox Exp $ +.\" +.hy 0 +.ad l +.\" Title: named +.\" Author: +.\" Generator: DocBook XSL Stylesheets v1.71.1 +.\" Date: June 30, 2000 +.\" Manual: BIND9 +.\" Source: BIND9 +.\" +.TH "NAMED" "8" "June 30, 2000" "BIND9" "BIND9" +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.SH "NAME" +named \- Internet domain name server +.SH "SYNOPSIS" +.HP 6 +\fBnamed\fR [\fB\-4\fR] [\fB\-6\fR] [\fB\-c\ \fR\fB\fIconfig\-file\fR\fR] [\fB\-d\ \fR\fB\fIdebug\-level\fR\fR] [\fB\-f\fR] [\fB\-g\fR] [\fB\-m\ \fR\fB\fIflag\fR\fR] [\fB\-n\ \fR\fB\fI#cpus\fR\fR] [\fB\-p\ \fR\fB\fIport\fR\fR] [\fB\-s\fR] [\fB\-S\ \fR\fB\fI#max\-socks\fR\fR] [\fB\-t\ \fR\fB\fIdirectory\fR\fR] [\fB\-u\ \fR\fB\fIuser\fR\fR] [\fB\-v\fR] [\fB\-x\ \fR\fB\fIcache\-file\fR\fR] +.SH "DESCRIPTION" +.PP +\fBnamed\fR +is a Domain Name System (DNS) server, part of the BIND 9 distribution from ISC. For more information on the DNS, see RFCs 1033, 1034, and 1035. +.PP +When invoked without arguments, +\fBnamed\fR +will read the default configuration file +\fI/etc/named.conf\fR, read any initial data, and listen for queries. +.SH "OPTIONS" +.PP +\-4 +.RS 4 +Use IPv4 only even if the host machine is capable of IPv6. +\fB\-4\fR +and +\fB\-6\fR +are mutually exclusive. +.RE +.PP +\-6 +.RS 4 +Use IPv6 only even if the host machine is capable of IPv4. +\fB\-4\fR +and +\fB\-6\fR +are mutually exclusive. +.RE +.PP +\-c \fIconfig\-file\fR +.RS 4 +Use +\fIconfig\-file\fR +as the configuration file instead of the default, +\fI/etc/named.conf\fR. To ensure that reloading the configuration file continues to work after the server has changed its working directory due to to a possible +\fBdirectory\fR +option in the configuration file, +\fIconfig\-file\fR +should be an absolute pathname. +.RE +.PP +\-d \fIdebug\-level\fR +.RS 4 +Set the daemon's debug level to +\fIdebug\-level\fR. Debugging traces from +\fBnamed\fR +become more verbose as the debug level increases. +.RE +.PP +\-f +.RS 4 +Run the server in the foreground (i.e. do not daemonize). +.RE +.PP +\-g +.RS 4 +Run the server in the foreground and force all logging to +\fIstderr\fR. +.RE +.PP +\-m \fIflag\fR +.RS 4 +Turn on memory usage debugging flags. Possible flags are +\fIusage\fR, +\fItrace\fR, +\fIrecord\fR, +\fIsize\fR, and +\fImctx\fR. These correspond to the ISC_MEM_DEBUGXXXX flags described in +\fI\fR. +.RE +.PP +\-n \fI#cpus\fR +.RS 4 +Create +\fI#cpus\fR +worker threads to take advantage of multiple CPUs. If not specified, +\fBnamed\fR +will try to determine the number of CPUs present and create one thread per CPU. If it is unable to determine the number of CPUs, a single worker thread will be created. +.RE +.PP +\-p \fIport\fR +.RS 4 +Listen for queries on port +\fIport\fR. If not specified, the default is port 53. +.RE +.PP +\-s +.RS 4 +Write memory usage statistics to +\fIstdout\fR +on exit. +.RS +.B "Note:" +This option is mainly of interest to BIND 9 developers and may be removed or changed in a future release. +.RE +.RE +.PP +\-S \fI#max\-socks\fR +.RS 4 +Allow +\fBnamed\fR +to use up to +\fI#max\-socks\fR +sockets. +.RS +.B "Warning:" +This option should be unnecessary for the vast majority of users. The use of this option could even be harmful because the specified value may exceed the limitation of the underlying system API. It is therefore set only when the default configuration causes exhaustion of file descriptors and the operational environment is known to support the specified number of sockets. Note also that the actual maximum number is normally a little fewer than the specified value because +\fBnamed\fR +reserves some file descriptors for its internal use. +.RE +.RE +.PP +\-t \fIdirectory\fR +.RS 4 +Chroot to +\fIdirectory\fR +after processing the command line arguments, but before reading the configuration file. +.RS +.B "Warning:" +This option should be used in conjunction with the +\fB\-u\fR +option, as chrooting a process running as root doesn't enhance security on most systems; the way +\fBchroot(2)\fR +is defined allows a process with root privileges to escape a chroot jail. +.RE +.RE +.PP +\-u \fIuser\fR +.RS 4 +Setuid to +\fIuser\fR +after completing privileged operations, such as creating sockets that listen on privileged ports. +.RS +.B "Note:" +On Linux, +\fBnamed\fR +uses the kernel's capability mechanism to drop all root privileges except the ability to +\fBbind(2)\fR +to a privileged port and set process resource limits. Unfortunately, this means that the +\fB\-u\fR +option only works when +\fBnamed\fR +is run on kernel 2.2.18 or later, or kernel 2.3.99\-pre3 or later, since previous kernels did not allow privileges to be retained after +\fBsetuid(2)\fR. +.RE +.RE +.PP +\-v +.RS 4 +Report the version number and exit. +.RE +.PP +\-x \fIcache\-file\fR +.RS 4 +Load data from +\fIcache\-file\fR +into the cache of the default view. +.RS +.B "Warning:" +This option must not be used. It is only of interest to BIND 9 developers and may be removed or changed in a future release. +.RE +.RE +.SH "SIGNALS" +.PP +In routine operation, signals should not be used to control the nameserver; +\fBrndc\fR +should be used instead. +.PP +SIGHUP +.RS 4 +Force a reload of the server. +.RE +.PP +SIGINT, SIGTERM +.RS 4 +Shut down the server. +.RE +.PP +The result of sending any other signals to the server is undefined. +.SH "CONFIGURATION" +.PP +The +\fBnamed\fR +configuration file is too complex to describe in detail here. A complete description is provided in the +BIND 9 Administrator Reference Manual. +.SH "FILES" +.PP +\fI/etc/named.conf\fR +.RS 4 +The default configuration file. +.RE +.PP +\fI/var/run/named.pid\fR +.RS 4 +The default process\-id file. +.RE +.SH "SEE ALSO" +.PP +RFC 1033, +RFC 1034, +RFC 1035, +\fBnamed\-checkconf\fR(8), +\fBnamed\-checkzone\fR(8), +\fBrndc\fR(8), +\fBlwresd\fR(8), +\fBnamed.conf\fR(5), +BIND 9 Administrator Reference Manual. +.SH "AUTHOR" +.PP +Internet Systems Consortium +.SH "COPYRIGHT" +Copyright \(co 2004\-2008 Internet Systems Consortium, Inc. ("ISC") +.br +Copyright \(co 2000, 2001, 2003 Internet Software Consortium. +.br diff --git a/contrib/bind-9.5.2/bin/named/named.conf.5 b/contrib/bind-9.5.2/bin/named/named.conf.5 new file mode 100644 index 0000000000..9a243195dd --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/named.conf.5 @@ -0,0 +1,540 @@ +.\" Copyright (C) 2004-2008 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: named.conf.5,v 1.31.38.2 2009/07/11 01:43:28 tbox Exp $ +.\" +.hy 0 +.ad l +.\" Title: \fInamed.conf\fR +.\" Author: +.\" Generator: DocBook XSL Stylesheets v1.71.1 +.\" Date: Aug 13, 2004 +.\" Manual: BIND9 +.\" Source: BIND9 +.\" +.TH "\fINAMED.CONF\fR" "5" "Aug 13, 2004" "BIND9" "BIND9" +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.SH "NAME" +named.conf \- configuration file for named +.SH "SYNOPSIS" +.HP 11 +\fBnamed.conf\fR +.SH "DESCRIPTION" +.PP +\fInamed.conf\fR +is the configuration file for +\fBnamed\fR. Statements are enclosed in braces and terminated with a semi\-colon. Clauses in the statements are also semi\-colon terminated. The usual comment styles are supported: +.PP +C style: /* */ +.PP +C++ style: // to end of line +.PP +Unix style: # to end of line +.SH "ACL" +.sp +.RS 4 +.nf +acl \fIstring\fR { \fIaddress_match_element\fR; ... }; +.fi +.RE +.SH "KEY" +.sp +.RS 4 +.nf +key \fIdomain_name\fR { + algorithm \fIstring\fR; + secret \fIstring\fR; +}; +.fi +.RE +.SH "MASTERS" +.sp +.RS 4 +.nf +masters \fIstring\fR [ port \fIinteger\fR ] { + ( \fImasters\fR | \fIipv4_address\fR [port \fIinteger\fR] | + \fIipv6_address\fR [port \fIinteger\fR] ) [ key \fIstring\fR ]; ... +}; +.fi +.RE +.SH "SERVER" +.sp +.RS 4 +.nf +server ( \fIipv4_address\fR\fI[/prefixlen]\fR | \fIipv6_address\fR\fI[/prefixlen]\fR ) { + bogus \fIboolean\fR; + edns \fIboolean\fR; + edns\-udp\-size \fIinteger\fR; + max\-udp\-size \fIinteger\fR; + provide\-ixfr \fIboolean\fR; + request\-ixfr \fIboolean\fR; + keys \fIserver_key\fR; + transfers \fIinteger\fR; + transfer\-format ( many\-answers | one\-answer ); + transfer\-source ( \fIipv4_address\fR | * ) + [ port ( \fIinteger\fR | * ) ]; + transfer\-source\-v6 ( \fIipv6_address\fR | * ) + [ port ( \fIinteger\fR | * ) ]; + support\-ixfr \fIboolean\fR; // obsolete +}; +.fi +.RE +.SH "TRUSTED\-KEYS" +.sp +.RS 4 +.nf +trusted\-keys { + \fIdomain_name\fR \fIflags\fR \fIprotocol\fR \fIalgorithm\fR \fIkey\fR; ... +}; +.fi +.RE +.SH "CONTROLS" +.sp +.RS 4 +.nf +controls { + inet ( \fIipv4_address\fR | \fIipv6_address\fR | * ) + [ port ( \fIinteger\fR | * ) ] + allow { \fIaddress_match_element\fR; ... } + [ keys { \fIstring\fR; ... } ]; + unix \fIunsupported\fR; // not implemented +}; +.fi +.RE +.SH "LOGGING" +.sp +.RS 4 +.nf +logging { + channel \fIstring\fR { + file \fIlog_file\fR; + syslog \fIoptional_facility\fR; + null; + stderr; + severity \fIlog_severity\fR; + print\-time \fIboolean\fR; + print\-severity \fIboolean\fR; + print\-category \fIboolean\fR; + }; + category \fIstring\fR { \fIstring\fR; ... }; +}; +.fi +.RE +.SH "LWRES" +.sp +.RS 4 +.nf +lwres { + listen\-on [ port \fIinteger\fR ] { + ( \fIipv4_address\fR | \fIipv6_address\fR ) [ port \fIinteger\fR ]; ... + }; + view \fIstring\fR \fIoptional_class\fR; + search { \fIstring\fR; ... }; + ndots \fIinteger\fR; +}; +.fi +.RE +.SH "OPTIONS" +.sp +.RS 4 +.nf +options { + avoid\-v4\-udp\-ports { \fIport\fR; ... }; + avoid\-v6\-udp\-ports { \fIport\fR; ... }; + blackhole { \fIaddress_match_element\fR; ... }; + coresize \fIsize\fR; + datasize \fIsize\fR; + directory \fIquoted_string\fR; + dump\-file \fIquoted_string\fR; + files \fIsize\fR; + heartbeat\-interval \fIinteger\fR; + host\-statistics \fIboolean\fR; // not implemented + host\-statistics\-max \fInumber\fR; // not implemented + hostname ( \fIquoted_string\fR | none ); + interface\-interval \fIinteger\fR; + listen\-on [ port \fIinteger\fR ] { \fIaddress_match_element\fR; ... }; + listen\-on\-v6 [ port \fIinteger\fR ] { \fIaddress_match_element\fR; ... }; + match\-mapped\-addresses \fIboolean\fR; + memstatistics\-file \fIquoted_string\fR; + pid\-file ( \fIquoted_string\fR | none ); + port \fIinteger\fR; + querylog \fIboolean\fR; + recursing\-file \fIquoted_string\fR; + reserved\-sockets \fIinteger\fR; + random\-device \fIquoted_string\fR; + recursive\-clients \fIinteger\fR; + serial\-query\-rate \fIinteger\fR; + server\-id ( \fIquoted_string\fR | none |; + stacksize \fIsize\fR; + statistics\-file \fIquoted_string\fR; + statistics\-interval \fIinteger\fR; // not yet implemented + tcp\-clients \fIinteger\fR; + tcp\-listen\-queue \fIinteger\fR; + tkey\-dhkey \fIquoted_string\fR \fIinteger\fR; + tkey\-gssapi\-credential \fIquoted_string\fR; + tkey\-domain \fIquoted_string\fR; + transfers\-per\-ns \fIinteger\fR; + transfers\-in \fIinteger\fR; + transfers\-out \fIinteger\fR; + use\-ixfr \fIboolean\fR; + version ( \fIquoted_string\fR | none ); + allow\-recursion { \fIaddress_match_element\fR; ... }; + allow\-recursion\-on { \fIaddress_match_element\fR; ... }; + sortlist { \fIaddress_match_element\fR; ... }; + topology { \fIaddress_match_element\fR; ... }; // not implemented + auth\-nxdomain \fIboolean\fR; // default changed + minimal\-responses \fIboolean\fR; + recursion \fIboolean\fR; + rrset\-order { + [ class \fIstring\fR ] [ type \fIstring\fR ] + [ name \fIquoted_string\fR ] \fIstring\fR \fIstring\fR; ... + }; + provide\-ixfr \fIboolean\fR; + request\-ixfr \fIboolean\fR; + rfc2308\-type1 \fIboolean\fR; // not yet implemented + additional\-from\-auth \fIboolean\fR; + additional\-from\-cache \fIboolean\fR; + query\-source ( ( \fIipv4_address\fR | * ) | [ address ( \fIipv4_address\fR | * ) ] ) [ port ( \fIinteger\fR | * ) ]; + query\-source\-v6 ( ( \fIipv6_address\fR | * ) | [ address ( \fIipv6_address\fR | * ) ] ) [ port ( \fIinteger\fR | * ) ]; + use\-queryport\-pool \fIboolean\fR; + queryport\-pool\-ports \fIinteger\fR; + queryport\-pool\-updateinterval \fIinteger\fR; + cleaning\-interval \fIinteger\fR; + min\-roots \fIinteger\fR; // not implemented + lame\-ttl \fIinteger\fR; + max\-ncache\-ttl \fIinteger\fR; + max\-cache\-ttl \fIinteger\fR; + transfer\-format ( many\-answers | one\-answer ); + max\-cache\-size \fIsize\fR; + max\-acache\-size \fIsize\fR; + clients\-per\-query \fInumber\fR; + max\-clients\-per\-query \fInumber\fR; + check\-names ( master | slave | response ) + ( fail | warn | ignore ); + check\-mx ( fail | warn | ignore ); + check\-integrity \fIboolean\fR; + check\-mx\-cname ( fail | warn | ignore ); + check\-srv\-cname ( fail | warn | ignore ); + cache\-file \fIquoted_string\fR; // test option + suppress\-initial\-notify \fIboolean\fR; // not yet implemented + preferred\-glue \fIstring\fR; + dual\-stack\-servers [ port \fIinteger\fR ] { + ( \fIquoted_string\fR [port \fIinteger\fR] | + \fIipv4_address\fR [port \fIinteger\fR] | + \fIipv6_address\fR [port \fIinteger\fR] ); ... + }; + edns\-udp\-size \fIinteger\fR; + max\-udp\-size \fIinteger\fR; + root\-delegation\-only [ exclude { \fIquoted_string\fR; ... } ]; + disable\-algorithms \fIstring\fR { \fIstring\fR; ... }; + dnssec\-enable \fIboolean\fR; + dnssec\-validation \fIboolean\fR; + dnssec\-lookaside \fIstring\fR trust\-anchor \fIstring\fR; + dnssec\-must\-be\-secure \fIstring\fR \fIboolean\fR; + dnssec\-accept\-expired \fIboolean\fR; + empty\-server \fIstring\fR; + empty\-contact \fIstring\fR; + empty\-zones\-enable \fIboolean\fR; + disable\-empty\-zone \fIstring\fR; + dialup \fIdialuptype\fR; + ixfr\-from\-differences \fIixfrdiff\fR; + allow\-query { \fIaddress_match_element\fR; ... }; + allow\-query\-on { \fIaddress_match_element\fR; ... }; + allow\-query\-cache { \fIaddress_match_element\fR; ... }; + allow\-query\-cache\-on { \fIaddress_match_element\fR; ... }; + allow\-transfer { \fIaddress_match_element\fR; ... }; + allow\-update { \fIaddress_match_element\fR; ... }; + allow\-update\-forwarding { \fIaddress_match_element\fR; ... }; + update\-check\-ksk \fIboolean\fR; + masterfile\-format ( text | raw ); + notify \fInotifytype\fR; + notify\-source ( \fIipv4_address\fR | * ) [ port ( \fIinteger\fR | * ) ]; + notify\-source\-v6 ( \fIipv6_address\fR | * ) [ port ( \fIinteger\fR | * ) ]; + notify\-delay \fIseconds\fR; + notify\-to\-soa \fIboolean\fR; + also\-notify [ port \fIinteger\fR ] { ( \fIipv4_address\fR | \fIipv6_address\fR ) + [ port \fIinteger\fR ]; ... }; + allow\-notify { \fIaddress_match_element\fR; ... }; + forward ( first | only ); + forwarders [ port \fIinteger\fR ] { + ( \fIipv4_address\fR | \fIipv6_address\fR ) [ port \fIinteger\fR ]; ... + }; + max\-journal\-size \fIsize_no_default\fR; + max\-transfer\-time\-in \fIinteger\fR; + max\-transfer\-time\-out \fIinteger\fR; + max\-transfer\-idle\-in \fIinteger\fR; + max\-transfer\-idle\-out \fIinteger\fR; + max\-retry\-time \fIinteger\fR; + min\-retry\-time \fIinteger\fR; + max\-refresh\-time \fIinteger\fR; + min\-refresh\-time \fIinteger\fR; + multi\-master \fIboolean\fR; + sig\-validity\-interval \fIinteger\fR; + transfer\-source ( \fIipv4_address\fR | * ) + [ port ( \fIinteger\fR | * ) ]; + transfer\-source\-v6 ( \fIipv6_address\fR | * ) + [ port ( \fIinteger\fR | * ) ]; + alt\-transfer\-source ( \fIipv4_address\fR | * ) + [ port ( \fIinteger\fR | * ) ]; + alt\-transfer\-source\-v6 ( \fIipv6_address\fR | * ) + [ port ( \fIinteger\fR | * ) ]; + use\-alt\-transfer\-source \fIboolean\fR; + zone\-statistics \fIboolean\fR; + key\-directory \fIquoted_string\fR; + try\-tcp\-refresh \fIboolean\fR; + zero\-no\-soa\-ttl \fIboolean\fR; + zero\-no\-soa\-ttl\-cache \fIboolean\fR; + allow\-v6\-synthesis { \fIaddress_match_element\fR; ... }; // obsolete + deallocate\-on\-exit \fIboolean\fR; // obsolete + fake\-iquery \fIboolean\fR; // obsolete + fetch\-glue \fIboolean\fR; // obsolete + has\-old\-clients \fIboolean\fR; // obsolete + maintain\-ixfr\-base \fIboolean\fR; // obsolete + max\-ixfr\-log\-size \fIsize\fR; // obsolete + multiple\-cnames \fIboolean\fR; // obsolete + named\-xfer \fIquoted_string\fR; // obsolete + serial\-queries \fIinteger\fR; // obsolete + treat\-cr\-as\-space \fIboolean\fR; // obsolete + use\-id\-pool \fIboolean\fR; // obsolete +}; +.fi +.RE +.SH "VIEW" +.sp +.RS 4 +.nf +view \fIstring\fR \fIoptional_class\fR { + match\-clients { \fIaddress_match_element\fR; ... }; + match\-destinations { \fIaddress_match_element\fR; ... }; + match\-recursive\-only \fIboolean\fR; + key \fIstring\fR { + algorithm \fIstring\fR; + secret \fIstring\fR; + }; + zone \fIstring\fR \fIoptional_class\fR { + ... + }; + server ( \fIipv4_address\fR\fI[/prefixlen]\fR | \fIipv6_address\fR\fI[/prefixlen]\fR ) { + ... + }; + trusted\-keys { + \fIstring\fR \fIinteger\fR \fIinteger\fR \fIinteger\fR \fIquoted_string\fR; ... + }; + allow\-recursion { \fIaddress_match_element\fR; ... }; + allow\-recursion\-on { \fIaddress_match_element\fR; ... }; + sortlist { \fIaddress_match_element\fR; ... }; + topology { \fIaddress_match_element\fR; ... }; // not implemented + auth\-nxdomain \fIboolean\fR; // default changed + minimal\-responses \fIboolean\fR; + recursion \fIboolean\fR; + rrset\-order { + [ class \fIstring\fR ] [ type \fIstring\fR ] + [ name \fIquoted_string\fR ] \fIstring\fR \fIstring\fR; ... + }; + provide\-ixfr \fIboolean\fR; + request\-ixfr \fIboolean\fR; + rfc2308\-type1 \fIboolean\fR; // not yet implemented + additional\-from\-auth \fIboolean\fR; + additional\-from\-cache \fIboolean\fR; + query\-source ( ( \fIipv4_address\fR | * ) | [ address ( \fIipv4_address\fR | * ) ] ) [ port ( \fIinteger\fR | * ) ]; + query\-source\-v6 ( ( \fIipv6_address\fR | * ) | [ address ( \fIipv6_address\fR | * ) ] ) [ port ( \fIinteger\fR | * ) ]; + use\-queryport\-pool \fIboolean\fR; + queryport\-pool\-ports \fIinteger\fR; + queryport\-pool\-updateinterval \fIinteger\fR; + cleaning\-interval \fIinteger\fR; + min\-roots \fIinteger\fR; // not implemented + lame\-ttl \fIinteger\fR; + max\-ncache\-ttl \fIinteger\fR; + max\-cache\-ttl \fIinteger\fR; + transfer\-format ( many\-answers | one\-answer ); + max\-cache\-size \fIsize\fR; + max\-acache\-size \fIsize\fR; + clients\-per\-query \fInumber\fR; + max\-clients\-per\-query \fInumber\fR; + check\-names ( master | slave | response ) + ( fail | warn | ignore ); + check\-mx ( fail | warn | ignore ); + check\-integrity \fIboolean\fR; + check\-mx\-cname ( fail | warn | ignore ); + check\-srv\-cname ( fail | warn | ignore ); + cache\-file \fIquoted_string\fR; // test option + suppress\-initial\-notify \fIboolean\fR; // not yet implemented + preferred\-glue \fIstring\fR; + dual\-stack\-servers [ port \fIinteger\fR ] { + ( \fIquoted_string\fR [port \fIinteger\fR] | + \fIipv4_address\fR [port \fIinteger\fR] | + \fIipv6_address\fR [port \fIinteger\fR] ); ... + }; + edns\-udp\-size \fIinteger\fR; + max\-udp\-size \fIinteger\fR; + root\-delegation\-only [ exclude { \fIquoted_string\fR; ... } ]; + disable\-algorithms \fIstring\fR { \fIstring\fR; ... }; + dnssec\-enable \fIboolean\fR; + dnssec\-validation \fIboolean\fR; + dnssec\-lookaside \fIstring\fR trust\-anchor \fIstring\fR; + dnssec\-must\-be\-secure \fIstring\fR \fIboolean\fR; + dnssec\-accept\-expired \fIboolean\fR; + empty\-server \fIstring\fR; + empty\-contact \fIstring\fR; + empty\-zones\-enable \fIboolean\fR; + disable\-empty\-zone \fIstring\fR; + dialup \fIdialuptype\fR; + ixfr\-from\-differences \fIixfrdiff\fR; + allow\-query { \fIaddress_match_element\fR; ... }; + allow\-query\-on { \fIaddress_match_element\fR; ... }; + allow\-query\-cache { \fIaddress_match_element\fR; ... }; + allow\-query\-cache\-on { \fIaddress_match_element\fR; ... }; + allow\-transfer { \fIaddress_match_element\fR; ... }; + allow\-update { \fIaddress_match_element\fR; ... }; + allow\-update\-forwarding { \fIaddress_match_element\fR; ... }; + update\-check\-ksk \fIboolean\fR; + masterfile\-format ( text | raw ); + notify \fInotifytype\fR; + notify\-source ( \fIipv4_address\fR | * ) [ port ( \fIinteger\fR | * ) ]; + notify\-source\-v6 ( \fIipv6_address\fR | * ) [ port ( \fIinteger\fR | * ) ]; + notify\-delay \fIseconds\fR; + notify\-to\-soa \fIboolean\fR; + also\-notify [ port \fIinteger\fR ] { ( \fIipv4_address\fR | \fIipv6_address\fR ) + [ port \fIinteger\fR ]; ... }; + allow\-notify { \fIaddress_match_element\fR; ... }; + forward ( first | only ); + forwarders [ port \fIinteger\fR ] { + ( \fIipv4_address\fR | \fIipv6_address\fR ) [ port \fIinteger\fR ]; ... + }; + max\-journal\-size \fIsize_no_default\fR; + max\-transfer\-time\-in \fIinteger\fR; + max\-transfer\-time\-out \fIinteger\fR; + max\-transfer\-idle\-in \fIinteger\fR; + max\-transfer\-idle\-out \fIinteger\fR; + max\-retry\-time \fIinteger\fR; + min\-retry\-time \fIinteger\fR; + max\-refresh\-time \fIinteger\fR; + min\-refresh\-time \fIinteger\fR; + multi\-master \fIboolean\fR; + sig\-validity\-interval \fIinteger\fR; + transfer\-source ( \fIipv4_address\fR | * ) + [ port ( \fIinteger\fR | * ) ]; + transfer\-source\-v6 ( \fIipv6_address\fR | * ) + [ port ( \fIinteger\fR | * ) ]; + alt\-transfer\-source ( \fIipv4_address\fR | * ) + [ port ( \fIinteger\fR | * ) ]; + alt\-transfer\-source\-v6 ( \fIipv6_address\fR | * ) + [ port ( \fIinteger\fR | * ) ]; + use\-alt\-transfer\-source \fIboolean\fR; + zone\-statistics \fIboolean\fR; + try\-tcp\-refresh \fIboolean\fR; + key\-directory \fIquoted_string\fR; + zero\-no\-soa\-ttl \fIboolean\fR; + zero\-no\-soa\-ttl\-cache \fIboolean\fR; + allow\-v6\-synthesis { \fIaddress_match_element\fR; ... }; // obsolete + fetch\-glue \fIboolean\fR; // obsolete + maintain\-ixfr\-base \fIboolean\fR; // obsolete + max\-ixfr\-log\-size \fIsize\fR; // obsolete +}; +.fi +.RE +.SH "ZONE" +.sp +.RS 4 +.nf +zone \fIstring\fR \fIoptional_class\fR { + type ( master | slave | stub | hint | + forward | delegation\-only ); + file \fIquoted_string\fR; + masters [ port \fIinteger\fR ] { + ( \fImasters\fR | + \fIipv4_address\fR [port \fIinteger\fR] | + \fIipv6_address\fR [ port \fIinteger\fR ] ) [ key \fIstring\fR ]; ... + }; + database \fIstring\fR; + delegation\-only \fIboolean\fR; + check\-names ( fail | warn | ignore ); + check\-mx ( fail | warn | ignore ); + check\-integrity \fIboolean\fR; + check\-mx\-cname ( fail | warn | ignore ); + check\-srv\-cname ( fail | warn | ignore ); + dialup \fIdialuptype\fR; + ixfr\-from\-differences \fIboolean\fR; + journal \fIquoted_string\fR; + zero\-no\-soa\-ttl \fIboolean\fR; + allow\-query { \fIaddress_match_element\fR; ... }; + allow\-query\-on { \fIaddress_match_element\fR; ... }; + allow\-transfer { \fIaddress_match_element\fR; ... }; + allow\-update { \fIaddress_match_element\fR; ... }; + allow\-update\-forwarding { \fIaddress_match_element\fR; ... }; + update\-policy { + ( grant | deny ) \fIstring\fR + ( name | subdomain | wildcard | self ) \fIstring\fR + \fIrrtypelist\fR; ... + }; + update\-check\-ksk \fIboolean\fR; + masterfile\-format ( text | raw ); + notify \fInotifytype\fR; + notify\-source ( \fIipv4_address\fR | * ) [ port ( \fIinteger\fR | * ) ]; + notify\-source\-v6 ( \fIipv6_address\fR | * ) [ port ( \fIinteger\fR | * ) ]; + notify\-delay \fIseconds\fR; + notify\-to\-soa \fIboolean\fR; + also\-notify [ port \fIinteger\fR ] { ( \fIipv4_address\fR | \fIipv6_address\fR ) + [ port \fIinteger\fR ]; ... }; + allow\-notify { \fIaddress_match_element\fR; ... }; + forward ( first | only ); + forwarders [ port \fIinteger\fR ] { + ( \fIipv4_address\fR | \fIipv6_address\fR ) [ port \fIinteger\fR ]; ... + }; + max\-journal\-size \fIsize_no_default\fR; + max\-transfer\-time\-in \fIinteger\fR; + max\-transfer\-time\-out \fIinteger\fR; + max\-transfer\-idle\-in \fIinteger\fR; + max\-transfer\-idle\-out \fIinteger\fR; + max\-retry\-time \fIinteger\fR; + min\-retry\-time \fIinteger\fR; + max\-refresh\-time \fIinteger\fR; + min\-refresh\-time \fIinteger\fR; + multi\-master \fIboolean\fR; + sig\-validity\-interval \fIinteger\fR; + transfer\-source ( \fIipv4_address\fR | * ) + [ port ( \fIinteger\fR | * ) ]; + transfer\-source\-v6 ( \fIipv6_address\fR | * ) + [ port ( \fIinteger\fR | * ) ]; + alt\-transfer\-source ( \fIipv4_address\fR | * ) + [ port ( \fIinteger\fR | * ) ]; + alt\-transfer\-source\-v6 ( \fIipv6_address\fR | * ) + [ port ( \fIinteger\fR | * ) ]; + use\-alt\-transfer\-source \fIboolean\fR; + zone\-statistics \fIboolean\fR; + try\-tcp\-refresh \fIboolean\fR; + key\-directory \fIquoted_string\fR; + ixfr\-base \fIquoted_string\fR; // obsolete + ixfr\-tmp\-file \fIquoted_string\fR; // obsolete + maintain\-ixfr\-base \fIboolean\fR; // obsolete + max\-ixfr\-log\-size \fIsize\fR; // obsolete + pubkey \fIinteger\fR \fIinteger\fR \fIinteger\fR \fIquoted_string\fR; // obsolete +}; +.fi +.RE +.SH "FILES" +.PP +\fI/etc/named.conf\fR +.SH "SEE ALSO" +.PP +\fBnamed\fR(8), +\fBnamed\-checkconf\fR(8), +\fBrndc\fR(8), +BIND 9 Administrator Reference Manual. +.SH "COPYRIGHT" +Copyright \(co 2004\-2008 Internet Systems Consortium, Inc. ("ISC") +.br diff --git a/contrib/bind-9.5.2/bin/named/named.conf.html b/contrib/bind-9.5.2/bin/named/named.conf.html new file mode 100644 index 0000000000..ae056615ff --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/named.conf.html @@ -0,0 +1,574 @@ + + + + + +named.conf + + +
+
+
+

Name

+

named.conf — configuration file for named

+
+
+

Synopsis

+

named.conf

+
+
+

DESCRIPTION

+

named.conf is the configuration file + for + named. Statements are enclosed + in braces and terminated with a semi-colon. Clauses in + the statements are also semi-colon terminated. The usual + comment styles are supported: +

+

+ C style: /* */ +

+

+ C++ style: // to end of line +

+

+ Unix style: # to end of line +

+
+
+

ACL

+


+acl string { address_match_element; ... };
+
+

+
+
+

KEY

+


+key domain_name {
+ algorithm string;
+ secret string;
+};
+

+
+
+

MASTERS

+


+masters string [ port integer ] {
+ ( masters | ipv4_address [port integer] |
+ ipv6_address [port integer] ) [ key string ]; ...
+};
+

+
+
+

SERVER

+


+server ( ipv4_address[/prefixlen] | ipv6_address[/prefixlen] ) {
+ bogus boolean;
+ edns boolean;
+ edns-udp-size integer;
+ max-udp-size integer;
+ provide-ixfr boolean;
+ request-ixfr boolean;
+ keys server_key;
+ transfers integer;
+ transfer-format ( many-answers | one-answer );
+ transfer-source ( ipv4_address | * )
+ [ port ( integer | * ) ];
+ transfer-source-v6 ( ipv6_address | * )
+ [ port ( integer | * ) ];
+
+ support-ixfr boolean; // obsolete
+};
+

+
+
+

TRUSTED-KEYS

+


+trusted-keys {
+ domain_name flags protocol algorithm key; ... 
+};
+

+
+
+

CONTROLS

+


+controls {
+ inet ( ipv4_address | ipv6_address | * )
+ [ port ( integer | * ) ]
+ allow { address_match_element; ... }
+ [ keys { string; ... } ];
+ unix unsupported; // not implemented
+};
+

+
+
+

LOGGING

+


+logging {
+ channel string {
+ file log_file;
+ syslog optional_facility;
+ null;
+ stderr;
+ severity log_severity;
+ print-time boolean;
+ print-severity boolean;
+ print-category boolean;
+ };
+ category string { string; ... };
+};
+

+
+
+

LWRES

+


+lwres {
+ listen-on [ port integer ] {
+ ( ipv4_address | ipv6_address ) [ port integer ]; ...
+ };
+ view string optional_class;
+ search { string; ... };
+ ndots integer;
+};
+

+
+
+

OPTIONS

+


+options {
+ avoid-v4-udp-ports { port; ... };
+ avoid-v6-udp-ports { port; ... };
+ blackhole { address_match_element; ... };
+ coresize size;
+ datasize size;
+ directory quoted_string;
+ dump-file quoted_string;
+ files size;
+ heartbeat-interval integer;
+ host-statistics boolean; // not implemented
+ host-statistics-max number; // not implemented
+ hostname ( quoted_string | none );
+ interface-interval integer;
+ listen-on [ port integer ] { address_match_element; ... };
+ listen-on-v6 [ port integer ] { address_match_element; ... };
+ match-mapped-addresses boolean;
+ memstatistics-file quoted_string;
+ pid-file ( quoted_string | none );
+ port integer;
+ querylog boolean;
+ recursing-file quoted_string;
+ reserved-sockets integer;
+ random-device quoted_string;
+ recursive-clients integer;
+ serial-query-rate integer;
+ server-id ( quoted_string | none |;
+ stacksize size;
+ statistics-file quoted_string;
+ statistics-interval integer; // not yet implemented
+ tcp-clients integer;
+ tcp-listen-queue integer;
+ tkey-dhkey quoted_string integer;
+ tkey-gssapi-credential quoted_string;
+ tkey-domain quoted_string;
+ transfers-per-ns integer;
+ transfers-in integer;
+ transfers-out integer;
+ use-ixfr boolean;
+ version ( quoted_string | none );
+ allow-recursion { address_match_element; ... };
+ allow-recursion-on { address_match_element; ... };
+ sortlist { address_match_element; ... };
+ topology { address_match_element; ... }; // not implemented
+ auth-nxdomain boolean; // default changed
+ minimal-responses boolean;
+ recursion boolean;
+ rrset-order {
+ [ class string ] [ type string ]
+ [ name quoted_string string string; ...
+ };
+ provide-ixfr boolean;
+ request-ixfr boolean;
+ rfc2308-type1 boolean; // not yet implemented
+ additional-from-auth boolean;
+ additional-from-cache boolean;
+ query-source ( ( ipv4_address | * ) | [ address ( ipv4_address | * ) ] ) [ port ( integer | * ) ];
+ query-source-v6 ( ( ipv6_address | * ) | [ address ( ipv6_address | * ) ] ) [ port ( integer | * ) ];
+ use-queryport-pool boolean;
+ queryport-pool-ports integer;
+ queryport-pool-updateinterval integer;
+ cleaning-interval integer;
+ min-roots integer; // not implemented
+ lame-ttl integer;
+ max-ncache-ttl integer;
+ max-cache-ttl integer;
+ transfer-format ( many-answers | one-answer );
+ max-cache-size size;
+ max-acache-size size;
+ clients-per-query number;
+ max-clients-per-query number;
+ check-names ( master | slave | response )
+ ( fail | warn | ignore );
+ check-mx ( fail | warn | ignore );
+ check-integrity boolean;
+ check-mx-cname ( fail | warn | ignore );
+ check-srv-cname ( fail | warn | ignore );
+ cache-file quoted_string; // test option
+ suppress-initial-notify boolean; // not yet implemented
+ preferred-glue string;
+ dual-stack-servers [ port integer ] {
+ ( quoted_string [port integer] |
+ ipv4_address [port integer] |
+ ipv6_address [port integer] ); ...
+ };
+ edns-udp-size integer;
+ max-udp-size integer;
+ root-delegation-only [ exclude { quoted_string; ... } ];
+ disable-algorithms string { string; ... };
+ dnssec-enable boolean;
+ dnssec-validation boolean;
+ dnssec-lookaside string trust-anchor string;
+ dnssec-must-be-secure string boolean;
+ dnssec-accept-expired boolean;
+
+ empty-server string;
+ empty-contact string;
+ empty-zones-enable boolean;
+ disable-empty-zone string;
+
+ dialup dialuptype;
+ ixfr-from-differences ixfrdiff;
+
+ allow-query { address_match_element; ... };
+ allow-query-on { address_match_element; ... };
+ allow-query-cache { address_match_element; ... };
+ allow-query-cache-on { address_match_element; ... };
+ allow-transfer { address_match_element; ... };
+ allow-update { address_match_element; ... };
+ allow-update-forwarding { address_match_element; ... };
+ update-check-ksk boolean;
+
+ masterfile-format ( text | raw );
+ notify notifytype;
+ notify-source ( ipv4_address | * ) [ port ( integer | * ) ];
+ notify-source-v6 ( ipv6_address | * ) [ port ( integer | * ) ];
+ notify-delay seconds;
+ notify-to-soa boolean;
+ also-notify [ port integer ] { ( ipv4_address | ipv6_address )
+ [ port integer ]; ... };
+ allow-notify { address_match_element; ... };
+
+ forward ( first | only );
+ forwarders [ port integer ] {
+ ( ipv4_address | ipv6_address ) [ port integer ]; ...
+ };
+
+ max-journal-size size_no_default;
+ max-transfer-time-in integer;
+ max-transfer-time-out integer;
+ max-transfer-idle-in integer;
+ max-transfer-idle-out integer;
+ max-retry-time integer;
+ min-retry-time integer;
+ max-refresh-time integer;
+ min-refresh-time integer;
+ multi-master boolean;
+ sig-validity-interval integer;
+
+ transfer-source ( ipv4_address | * )
+ [ port ( integer | * ) ];
+ transfer-source-v6 ( ipv6_address | * )
+ [ port ( integer | * ) ];
+
+ alt-transfer-source ( ipv4_address | * )
+ [ port ( integer | * ) ];
+ alt-transfer-source-v6 ( ipv6_address | * )
+ [ port ( integer | * ) ];
+ use-alt-transfer-source boolean;
+
+ zone-statistics boolean;
+ key-directory quoted_string;
+ try-tcp-refresh boolean;
+ zero-no-soa-ttl boolean;
+ zero-no-soa-ttl-cache boolean;
+
+ allow-v6-synthesis { address_match_element; ... }; // obsolete
+ deallocate-on-exit boolean; // obsolete
+ fake-iquery boolean; // obsolete
+ fetch-glue boolean; // obsolete
+ has-old-clients boolean; // obsolete
+ maintain-ixfr-base boolean; // obsolete
+ max-ixfr-log-size size; // obsolete
+ multiple-cnames boolean; // obsolete
+ named-xfer quoted_string; // obsolete
+ serial-queries integer; // obsolete
+ treat-cr-as-space boolean; // obsolete
+ use-id-pool boolean; // obsolete
+};
+

+
+
+

VIEW

+


+view string optional_class {
+ match-clients { address_match_element; ... };
+ match-destinations { address_match_element; ... };
+ match-recursive-only boolean;
+
+ key string {
+ algorithm string;
+ secret string;
+ };
+
+ zone string optional_class {
+ ...
+ };
+
+ server ( ipv4_address[/prefixlen] | ipv6_address[/prefixlen] ) {
+ ...
+ };
+
+ trusted-keys {
+ string integer integer integer quoted_string; ...
+ };
+
+ allow-recursion { address_match_element; ... };
+ allow-recursion-on { address_match_element; ... };
+ sortlist { address_match_element; ... };
+ topology { address_match_element; ... }; // not implemented
+ auth-nxdomain boolean; // default changed
+ minimal-responses boolean;
+ recursion boolean;
+ rrset-order {
+ [ class string ] [ type string ]
+ [ name quoted_string string string; ...
+ };
+ provide-ixfr boolean;
+ request-ixfr boolean;
+ rfc2308-type1 boolean; // not yet implemented
+ additional-from-auth boolean;
+ additional-from-cache boolean;
+ query-source ( ( ipv4_address | * ) | [ address ( ipv4_address | * ) ] ) [ port ( integer | * ) ];
+ query-source-v6 ( ( ipv6_address | * ) | [ address ( ipv6_address | * ) ] ) [ port ( integer | * ) ];
+ use-queryport-pool boolean;
+ queryport-pool-ports integer;
+ queryport-pool-updateinterval integer;
+ cleaning-interval integer;
+ min-roots integer; // not implemented
+ lame-ttl integer;
+ max-ncache-ttl integer;
+ max-cache-ttl integer;
+ transfer-format ( many-answers | one-answer );
+ max-cache-size size;
+ max-acache-size size;
+ clients-per-query number;
+ max-clients-per-query number;
+ check-names ( master | slave | response )
+ ( fail | warn | ignore );
+ check-mx ( fail | warn | ignore );
+ check-integrity boolean;
+ check-mx-cname ( fail | warn | ignore );
+ check-srv-cname ( fail | warn | ignore );
+ cache-file quoted_string; // test option
+ suppress-initial-notify boolean; // not yet implemented
+ preferred-glue string;
+ dual-stack-servers [ port integer ] {
+ ( quoted_string [port integer] |
+ ipv4_address [port integer] |
+ ipv6_address [port integer] ); ...
+ };
+ edns-udp-size integer;
+ max-udp-size integer;
+ root-delegation-only [ exclude { quoted_string; ... } ];
+ disable-algorithms string { string; ... };
+ dnssec-enable boolean;
+ dnssec-validation boolean;
+ dnssec-lookaside string trust-anchor string;
+ dnssec-must-be-secure string boolean;
+ dnssec-accept-expired boolean;
+
+ empty-server string;
+ empty-contact string;
+ empty-zones-enable boolean;
+ disable-empty-zone string;
+
+ dialup dialuptype;
+ ixfr-from-differences ixfrdiff;
+
+ allow-query { address_match_element; ... };
+ allow-query-on { address_match_element; ... };
+ allow-query-cache { address_match_element; ... };
+ allow-query-cache-on { address_match_element; ... };
+ allow-transfer { address_match_element; ... };
+ allow-update { address_match_element; ... };
+ allow-update-forwarding { address_match_element; ... };
+ update-check-ksk boolean;
+
+ masterfile-format ( text | raw );
+ notify notifytype;
+ notify-source ( ipv4_address | * ) [ port ( integer | * ) ];
+ notify-source-v6 ( ipv6_address | * ) [ port ( integer | * ) ];
+ notify-delay seconds;
+ notify-to-soa boolean;
+ also-notify [ port integer ] { ( ipv4_address | ipv6_address )
+ [ port integer ]; ... };
+ allow-notify { address_match_element; ... };
+
+ forward ( first | only );
+ forwarders [ port integer ] {
+ ( ipv4_address | ipv6_address ) [ port integer ]; ...
+ };
+
+ max-journal-size size_no_default;
+ max-transfer-time-in integer;
+ max-transfer-time-out integer;
+ max-transfer-idle-in integer;
+ max-transfer-idle-out integer;
+ max-retry-time integer;
+ min-retry-time integer;
+ max-refresh-time integer;
+ min-refresh-time integer;
+ multi-master boolean;
+ sig-validity-interval integer;
+
+ transfer-source ( ipv4_address | * )
+ [ port ( integer | * ) ];
+ transfer-source-v6 ( ipv6_address | * )
+ [ port ( integer | * ) ];
+
+ alt-transfer-source ( ipv4_address | * )
+ [ port ( integer | * ) ];
+ alt-transfer-source-v6 ( ipv6_address | * )
+ [ port ( integer | * ) ];
+ use-alt-transfer-source boolean;
+
+ zone-statistics boolean;
+ try-tcp-refresh boolean;
+ key-directory quoted_string;
+ zero-no-soa-ttl boolean;
+ zero-no-soa-ttl-cache boolean;
+
+ allow-v6-synthesis { address_match_element; ... }; // obsolete
+ fetch-glue boolean; // obsolete
+ maintain-ixfr-base boolean; // obsolete
+ max-ixfr-log-size size; // obsolete
+};
+

+
+
+

ZONE

+


+zone string optional_class {
+ type ( master | slave | stub | hint |
+ forward | delegation-only );
+ file quoted_string;
+
+ masters [ port integer ] {
+ ( masters |
+ ipv4_address [port integer] |
+ ipv6_address [ port integer ] ) [ key string ]; ...
+ };
+
+ database string;
+ delegation-only boolean;
+ check-names ( fail | warn | ignore );
+ check-mx ( fail | warn | ignore );
+ check-integrity boolean;
+ check-mx-cname ( fail | warn | ignore );
+ check-srv-cname ( fail | warn | ignore );
+ dialup dialuptype;
+ ixfr-from-differences boolean;
+ journal quoted_string;
+ zero-no-soa-ttl boolean;
+
+ allow-query { address_match_element; ... };
+ allow-query-on { address_match_element; ... };
+ allow-transfer { address_match_element; ... };
+ allow-update { address_match_element; ... };
+ allow-update-forwarding { address_match_element; ... };
+ update-policy {
+ ( grant | deny ) string
+ ( name | subdomain | wildcard | self ) string
+ rrtypelist; ...
+ };
+ update-check-ksk boolean;
+
+ masterfile-format ( text | raw );
+ notify notifytype;
+ notify-source ( ipv4_address | * ) [ port ( integer | * ) ];
+ notify-source-v6 ( ipv6_address | * ) [ port ( integer | * ) ];
+ notify-delay seconds;
+ notify-to-soa boolean;
+ also-notify [ port integer ] { ( ipv4_address | ipv6_address )
+ [ port integer ]; ... };
+ allow-notify { address_match_element; ... };
+
+ forward ( first | only );
+ forwarders [ port integer ] {
+ ( ipv4_address | ipv6_address ) [ port integer ]; ...
+ };
+
+ max-journal-size size_no_default;
+ max-transfer-time-in integer;
+ max-transfer-time-out integer;
+ max-transfer-idle-in integer;
+ max-transfer-idle-out integer;
+ max-retry-time integer;
+ min-retry-time integer;
+ max-refresh-time integer;
+ min-refresh-time integer;
+ multi-master boolean;
+ sig-validity-interval integer;
+
+ transfer-source ( ipv4_address | * )
+ [ port ( integer | * ) ];
+ transfer-source-v6 ( ipv6_address | * )
+ [ port ( integer | * ) ];
+
+ alt-transfer-source ( ipv4_address | * )
+ [ port ( integer | * ) ];
+ alt-transfer-source-v6 ( ipv6_address | * )
+ [ port ( integer | * ) ];
+ use-alt-transfer-source boolean;
+
+ zone-statistics boolean;
+ try-tcp-refresh boolean;
+ key-directory quoted_string;
+
+ ixfr-base quoted_string; // obsolete
+ ixfr-tmp-file quoted_string; // obsolete
+ maintain-ixfr-base boolean; // obsolete
+ max-ixfr-log-size size; // obsolete
+ pubkey integer integer integer quoted_string; // obsolete
+};
+

+
+
+

FILES

+

/etc/named.conf +

+
+
+

SEE ALSO

+

named(8), + named-checkconf(8), + rndc(8), + BIND 9 Administrator Reference Manual. +

+
+
+ diff --git a/contrib/bind-9.5.2/bin/named/named.html b/contrib/bind-9.5.2/bin/named/named.html new file mode 100644 index 0000000000..e934958e91 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/named.html @@ -0,0 +1,280 @@ + + + + + +named + + +
+
+
+

Name

+

named — Internet domain name server

+
+
+

Synopsis

+

named [-4] [-6] [-c config-file] [-d debug-level] [-f] [-g] [-m flag] [-n #cpus] [-p port] [-s] [-S #max-socks] [-t directory] [-u user] [-v] [-x cache-file]

+
+
+

DESCRIPTION

+

named + is a Domain Name System (DNS) server, + part of the BIND 9 distribution from ISC. For more + information on the DNS, see RFCs 1033, 1034, and 1035. +

+

+ When invoked without arguments, named + will + read the default configuration file + /etc/named.conf, read any initial + data, and listen for queries. +

+
+
+

OPTIONS

+
+
-4
+

+ Use IPv4 only even if the host machine is capable of IPv6. + -4 and -6 are mutually + exclusive. +

+
-6
+

+ Use IPv6 only even if the host machine is capable of IPv4. + -4 and -6 are mutually + exclusive. +

+
-c config-file
+

+ Use config-file as the + configuration file instead of the default, + /etc/named.conf. To + ensure that reloading the configuration file continues + to work after the server has changed its working + directory due to to a possible + directory option in the configuration + file, config-file should be + an absolute pathname. +

+
-d debug-level
+

+ Set the daemon's debug level to debug-level. + Debugging traces from named become + more verbose as the debug level increases. +

+
-f
+

+ Run the server in the foreground (i.e. do not daemonize). +

+
-g
+

+ Run the server in the foreground and force all logging + to stderr. +

+
-m flag
+

+ Turn on memory usage debugging flags. Possible flags are + usage, + trace, + record, + size, and + mctx. + These correspond to the ISC_MEM_DEBUGXXXX flags described in + <isc/mem.h>. +

+
-n #cpus
+

+ Create #cpus worker threads + to take advantage of multiple CPUs. If not specified, + named will try to determine the + number of CPUs present and create one thread per CPU. + If it is unable to determine the number of CPUs, a + single worker thread will be created. +

+
-p port
+

+ Listen for queries on port port. If not + specified, the default is port 53. +

+
-s
+
+

+ Write memory usage statistics to stdout on exit. +

+
+

Note

+

+ This option is mainly of interest to BIND 9 developers + and may be removed or changed in a future release. +

+
+
+
-S #max-socks
+
+

+ Allow named to use up to + #max-socks sockets. +

+
+

Warning

+

+ This option should be unnecessary for the vast majority + of users. + The use of this option could even be harmful because the + specified value may exceed the limitation of the + underlying system API. + It is therefore set only when the default configuration + causes exhaustion of file descriptors and the + operational environment is known to support the + specified number of sockets. + Note also that the actual maximum number is normally a little + fewer than the specified value because + named reserves some file descriptors + for its internal use. +

+
+
+
-t directory
+
+

Chroot + to directory after + processing the command line arguments, but before + reading the configuration file. +

+
+

Warning

+

+ This option should be used in conjunction with the + -u option, as chrooting a process + running as root doesn't enhance security on most + systems; the way chroot(2) is + defined allows a process with root privileges to + escape a chroot jail. +

+
+
+
-u user
+
+

Setuid + to user after completing + privileged operations, such as creating sockets that + listen on privileged ports. +

+
+

Note

+

+ On Linux, named uses the kernel's + capability mechanism to drop all root privileges + except the ability to bind(2) to + a + privileged port and set process resource limits. + Unfortunately, this means that the -u + option only works when named is + run + on kernel 2.2.18 or later, or kernel 2.3.99-pre3 or + later, since previous kernels did not allow privileges + to be retained after setuid(2). +

+
+
+
-v
+

+ Report the version number and exit. +

+
-x cache-file
+
+

+ Load data from cache-file into the + cache of the default view. +

+
+

Warning

+

+ This option must not be used. It is only of interest + to BIND 9 developers and may be removed or changed in a + future release. +

+
+
+
+
+
+

SIGNALS

+

+ In routine operation, signals should not be used to control + the nameserver; rndc should be used + instead. +

+
+
SIGHUP
+

+ Force a reload of the server. +

+
SIGINT, SIGTERM
+

+ Shut down the server. +

+
+

+ The result of sending any other signals to the server is undefined. +

+
+
+

CONFIGURATION

+

+ The named configuration file is too complex + to describe in detail here. A complete description is provided + in the + BIND 9 Administrator Reference Manual. +

+
+
+

FILES

+
+
/etc/named.conf
+

+ The default configuration file. +

+
/var/run/named.pid
+

+ The default process-id file. +

+
+
+
+

SEE ALSO

+

RFC 1033, + RFC 1034, + RFC 1035, + named-checkconf(8), + named-checkzone(8), + rndc(8), + lwresd(8), + named.conf(5), + BIND 9 Administrator Reference Manual. +

+
+
+

AUTHOR

+

Internet Systems Consortium +

+
+
+ diff --git a/contrib/bind-9.5.2/bin/named/notify.c b/contrib/bind-9.5.2/bin/named/notify.c new file mode 100644 index 0000000000..de52b8c82b --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/notify.c @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2003 Internet Software Consortium. + * + * 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: notify.c,v 1.37 2007/06/19 23:46:59 tbox Exp $ */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/*! \file + * \brief + * This module implements notify as in RFC1996. + */ + +static void +notify_log(ns_client_t *client, int level, const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + ns_client_logv(client, DNS_LOGCATEGORY_NOTIFY, NS_LOGMODULE_NOTIFY, + level, fmt, ap); + va_end(ap); +} + +static void +respond(ns_client_t *client, isc_result_t result) { + dns_rcode_t rcode; + dns_message_t *message; + isc_result_t msg_result; + + message = client->message; + rcode = dns_result_torcode(result); + + msg_result = dns_message_reply(message, ISC_TRUE); + if (msg_result != ISC_R_SUCCESS) + msg_result = dns_message_reply(message, ISC_FALSE); + if (msg_result != ISC_R_SUCCESS) { + ns_client_next(client, msg_result); + return; + } + message->rcode = rcode; + if (rcode == dns_rcode_noerror) + message->flags |= DNS_MESSAGEFLAG_AA; + else + message->flags &= ~DNS_MESSAGEFLAG_AA; + ns_client_send(client); +} + +void +ns_notify_start(ns_client_t *client) { + dns_message_t *request = client->message; + isc_result_t result; + dns_name_t *zonename; + dns_rdataset_t *zone_rdataset; + dns_zone_t *zone = NULL; + char namebuf[DNS_NAME_FORMATSIZE]; + char tsigbuf[DNS_NAME_FORMATSIZE + sizeof(": TSIG ''")]; + dns_tsigkey_t *tsigkey; + + /* + * Interpret the question section. + */ + result = dns_message_firstname(request, DNS_SECTION_QUESTION); + if (result != ISC_R_SUCCESS) { + notify_log(client, ISC_LOG_NOTICE, + "notify question section empty"); + goto formerr; + } + + /* + * The question section must contain exactly one question. + */ + zonename = NULL; + dns_message_currentname(request, DNS_SECTION_QUESTION, &zonename); + zone_rdataset = ISC_LIST_HEAD(zonename->list); + if (ISC_LIST_NEXT(zone_rdataset, link) != NULL) { + notify_log(client, ISC_LOG_NOTICE, + "notify question section contains multiple RRs"); + goto formerr; + } + + /* The zone section must have exactly one name. */ + result = dns_message_nextname(request, DNS_SECTION_ZONE); + if (result != ISC_R_NOMORE) { + notify_log(client, ISC_LOG_NOTICE, + "notify question section contains multiple RRs"); + goto formerr; + } + + /* The one rdataset must be an SOA. */ + if (zone_rdataset->type != dns_rdatatype_soa) { + notify_log(client, ISC_LOG_NOTICE, + "notify question section contains no SOA"); + goto formerr; + } + + tsigkey = dns_message_gettsigkey(request); + if (tsigkey != NULL) { + dns_name_format(&tsigkey->name, namebuf, sizeof(namebuf)); + + if (tsigkey->generated) { + char cnamebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(tsigkey->creator, cnamebuf, + sizeof(cnamebuf)); + snprintf(tsigbuf, sizeof(tsigbuf), ": TSIG '%s' (%s)", + namebuf, cnamebuf); + } else { + snprintf(tsigbuf, sizeof(tsigbuf), ": TSIG '%s'", + namebuf); + } + } else + tsigbuf[0] = '\0'; + dns_name_format(zonename, namebuf, sizeof(namebuf)); + result = dns_zt_find(client->view->zonetable, zonename, 0, NULL, + &zone); + if (result != ISC_R_SUCCESS) + goto notauth; + + switch (dns_zone_gettype(zone)) { + case dns_zone_master: + case dns_zone_slave: + case dns_zone_stub: /* Allow dialup passive to work. */ + notify_log(client, ISC_LOG_INFO, + "received notify for zone '%s'%s", namebuf, tsigbuf); + respond(client, dns_zone_notifyreceive(zone, + ns_client_getsockaddr(client), request)); + break; + default: + goto notauth; + } + dns_zone_detach(&zone); + return; + + notauth: + notify_log(client, ISC_LOG_NOTICE, + "received notify for zone '%s'%s: not authoritative", + namebuf, tsigbuf); + result = DNS_R_NOTAUTH; + goto failure; + + formerr: + result = DNS_R_FORMERR; + + failure: + if (zone != NULL) + dns_zone_detach(&zone); + respond(client, result); +} diff --git a/contrib/bind-9.5.2/bin/named/query.c b/contrib/bind-9.5.2/bin/named/query.c new file mode 100644 index 0000000000..08dc9c3f01 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/query.c @@ -0,0 +1,4742 @@ +/* + * Copyright (C) 2004-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 + * 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: query.c,v 1.298.48.15 2009/09/16 22:28:52 marka Exp $ */ + +/*! \file */ + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#ifdef DLZ +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/*% Partial answer? */ +#define PARTIALANSWER(c) (((c)->query.attributes & \ + NS_QUERYATTR_PARTIALANSWER) != 0) +/*% Use Cache? */ +#define USECACHE(c) (((c)->query.attributes & \ + NS_QUERYATTR_CACHEOK) != 0) +/*% Recursion OK? */ +#define RECURSIONOK(c) (((c)->query.attributes & \ + NS_QUERYATTR_RECURSIONOK) != 0) +/*% Recursing? */ +#define RECURSING(c) (((c)->query.attributes & \ + NS_QUERYATTR_RECURSING) != 0) +/*% Cache glue ok? */ +#define CACHEGLUEOK(c) (((c)->query.attributes & \ + NS_QUERYATTR_CACHEGLUEOK) != 0) +/*% Want Recursion? */ +#define WANTRECURSION(c) (((c)->query.attributes & \ + NS_QUERYATTR_WANTRECURSION) != 0) +/*% Want DNSSEC? */ +#define WANTDNSSEC(c) (((c)->attributes & \ + NS_CLIENTATTR_WANTDNSSEC) != 0) +/*% No authority? */ +#define NOAUTHORITY(c) (((c)->query.attributes & \ + NS_QUERYATTR_NOAUTHORITY) != 0) +/*% No additional? */ +#define NOADDITIONAL(c) (((c)->query.attributes & \ + NS_QUERYATTR_NOADDITIONAL) != 0) +/*% Secure? */ +#define SECURE(c) (((c)->query.attributes & \ + NS_QUERYATTR_SECURE) != 0) + +#if 0 +#define CTRACE(m) isc_log_write(ns_g_lctx, \ + NS_LOGCATEGORY_CLIENT, \ + NS_LOGMODULE_QUERY, \ + ISC_LOG_DEBUG(3), \ + "client %p: %s", client, (m)) +#define QTRACE(m) isc_log_write(ns_g_lctx, \ + NS_LOGCATEGORY_GENERAL, \ + NS_LOGMODULE_QUERY, \ + ISC_LOG_DEBUG(3), \ + "query %p: %s", query, (m)) +#else +#define CTRACE(m) ((void)m) +#define QTRACE(m) ((void)m) +#endif + +#define DNS_GETDB_NOEXACT 0x01U +#define DNS_GETDB_NOLOG 0x02U +#define DNS_GETDB_PARTIAL 0x04U + +typedef struct client_additionalctx { + ns_client_t *client; + dns_rdataset_t *rdataset; +} client_additionalctx_t; + +static isc_result_t +query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype); + +static isc_boolean_t +validate(ns_client_t *client, dns_db_t *db, dns_name_t *name, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset); + +static inline void +log_queryerror(ns_client_t *client, isc_result_t result, int line, int level); + +/*% + * Increment query statistics counters. + */ +static inline void +inc_stats(ns_client_t *client, isc_statscounter_t counter) { + dns_zone_t *zone = client->query.authzone; + + isc_stats_increment(ns_g_server->nsstats, counter); + + if (zone != NULL) { + isc_stats_t *zonestats = dns_zone_getrequeststats(zone); + if (zonestats != NULL) + isc_stats_increment(zonestats, counter); + } +} + +static void +query_send(ns_client_t *client) { + isc_statscounter_t counter; + if ((client->message->flags & DNS_MESSAGEFLAG_AA) == 0) + inc_stats(client, dns_nsstatscounter_nonauthans); + else + inc_stats(client, dns_nsstatscounter_authans); + if (client->message->rcode == dns_rcode_noerror) { + if (ISC_LIST_EMPTY(client->message->sections[DNS_SECTION_ANSWER])) { + if (client->query.isreferral) { + counter = dns_nsstatscounter_referral; + } else { + counter = dns_nsstatscounter_nxrrset; + } + } else { + counter = dns_nsstatscounter_success; + } + } else if (client->message->rcode == dns_rcode_nxdomain) { + counter = dns_nsstatscounter_nxdomain; + } else { + /* We end up here in case of YXDOMAIN, and maybe others */ + counter = dns_nsstatscounter_failure; + } + inc_stats(client, counter); + ns_client_send(client); +} + +static void +query_error(ns_client_t *client, isc_result_t result, int line) { + int loglevel = ISC_LOG_DEBUG(3); + + switch (result) { + case DNS_R_SERVFAIL: + loglevel = ISC_LOG_DEBUG(1); + inc_stats(client, dns_nsstatscounter_servfail); + break; + case DNS_R_FORMERR: + inc_stats(client, dns_nsstatscounter_formerr); + break; + default: + inc_stats(client, dns_nsstatscounter_failure); + break; + } + + log_queryerror(client, result, line, loglevel); + + ns_client_error(client, result); +} + +static void +query_next(ns_client_t *client, isc_result_t result) { + if (result == DNS_R_DUPLICATE) + inc_stats(client, dns_nsstatscounter_duplicate); + else if (result == DNS_R_DROP) + inc_stats(client, dns_nsstatscounter_dropped); + else + inc_stats(client, dns_nsstatscounter_failure); + ns_client_next(client, result); +} + +static inline void +query_freefreeversions(ns_client_t *client, isc_boolean_t everything) { + ns_dbversion_t *dbversion, *dbversion_next; + unsigned int i; + + for (dbversion = ISC_LIST_HEAD(client->query.freeversions), i = 0; + dbversion != NULL; + dbversion = dbversion_next, i++) + { + dbversion_next = ISC_LIST_NEXT(dbversion, link); + /* + * If we're not freeing everything, we keep the first three + * dbversions structures around. + */ + if (i > 3 || everything) { + ISC_LIST_UNLINK(client->query.freeversions, dbversion, + link); + isc_mem_put(client->mctx, dbversion, + sizeof(*dbversion)); + } + } +} + +void +ns_query_cancel(ns_client_t *client) { + LOCK(&client->query.fetchlock); + if (client->query.fetch != NULL) { + dns_resolver_cancelfetch(client->query.fetch); + + client->query.fetch = NULL; + } + UNLOCK(&client->query.fetchlock); +} + +static inline void +query_reset(ns_client_t *client, isc_boolean_t everything) { + isc_buffer_t *dbuf, *dbuf_next; + ns_dbversion_t *dbversion, *dbversion_next; + + /*% + * Reset the query state of a client to its default state. + */ + + /* + * Cancel the fetch if it's running. + */ + ns_query_cancel(client); + + /* + * Cleanup any active versions. + */ + for (dbversion = ISC_LIST_HEAD(client->query.activeversions); + dbversion != NULL; + dbversion = dbversion_next) { + dbversion_next = ISC_LIST_NEXT(dbversion, link); + dns_db_closeversion(dbversion->db, &dbversion->version, + ISC_FALSE); + dns_db_detach(&dbversion->db); + ISC_LIST_INITANDAPPEND(client->query.freeversions, + dbversion, link); + } + ISC_LIST_INIT(client->query.activeversions); + + if (client->query.authdb != NULL) + dns_db_detach(&client->query.authdb); + if (client->query.authzone != NULL) + dns_zone_detach(&client->query.authzone); + + query_freefreeversions(client, everything); + + for (dbuf = ISC_LIST_HEAD(client->query.namebufs); + dbuf != NULL; + dbuf = dbuf_next) { + dbuf_next = ISC_LIST_NEXT(dbuf, link); + if (dbuf_next != NULL || everything) { + ISC_LIST_UNLINK(client->query.namebufs, dbuf, link); + isc_buffer_free(&dbuf); + } + } + + if (client->query.restarts > 0) { + /* + * client->query.qname was dynamically allocated. + */ + dns_message_puttempname(client->message, + &client->query.qname); + } + client->query.qname = NULL; + client->query.attributes = (NS_QUERYATTR_RECURSIONOK | + NS_QUERYATTR_CACHEOK | + NS_QUERYATTR_SECURE); + client->query.restarts = 0; + client->query.timerset = ISC_FALSE; + client->query.origqname = NULL; + client->query.qname = NULL; + client->query.dboptions = 0; + client->query.fetchoptions = 0; + client->query.gluedb = NULL; + client->query.authdbset = ISC_FALSE; + client->query.isreferral = ISC_FALSE; +} + +static void +query_next_callback(ns_client_t *client) { + query_reset(client, ISC_FALSE); +} + +void +ns_query_free(ns_client_t *client) { + query_reset(client, ISC_TRUE); +} + +static inline isc_result_t +query_newnamebuf(ns_client_t *client) { + isc_buffer_t *dbuf; + isc_result_t result; + + CTRACE("query_newnamebuf"); + /*% + * Allocate a name buffer. + */ + + dbuf = NULL; + result = isc_buffer_allocate(client->mctx, &dbuf, 1024); + if (result != ISC_R_SUCCESS) { + CTRACE("query_newnamebuf: isc_buffer_allocate failed: done"); + return (result); + } + ISC_LIST_APPEND(client->query.namebufs, dbuf, link); + + CTRACE("query_newnamebuf: done"); + return (ISC_R_SUCCESS); +} + +static inline isc_buffer_t * +query_getnamebuf(ns_client_t *client) { + isc_buffer_t *dbuf; + isc_result_t result; + isc_region_t r; + + CTRACE("query_getnamebuf"); + /*% + * Return a name buffer with space for a maximal name, allocating + * a new one if necessary. + */ + + if (ISC_LIST_EMPTY(client->query.namebufs)) { + result = query_newnamebuf(client); + if (result != ISC_R_SUCCESS) { + CTRACE("query_getnamebuf: query_newnamebuf failed: done"); + return (NULL); + } + } + + dbuf = ISC_LIST_TAIL(client->query.namebufs); + INSIST(dbuf != NULL); + isc_buffer_availableregion(dbuf, &r); + if (r.length < 255) { + result = query_newnamebuf(client); + if (result != ISC_R_SUCCESS) { + CTRACE("query_getnamebuf: query_newnamebuf failed: done"); + return (NULL); + + } + dbuf = ISC_LIST_TAIL(client->query.namebufs); + isc_buffer_availableregion(dbuf, &r); + INSIST(r.length >= 255); + } + CTRACE("query_getnamebuf: done"); + return (dbuf); +} + +static inline void +query_keepname(ns_client_t *client, dns_name_t *name, isc_buffer_t *dbuf) { + isc_region_t r; + + CTRACE("query_keepname"); + /*% + * 'name' is using space in 'dbuf', but 'dbuf' has not yet been + * adjusted to take account of that. We do the adjustment. + */ + + REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) != 0); + + dns_name_toregion(name, &r); + isc_buffer_add(dbuf, r.length); + dns_name_setbuffer(name, NULL); + client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED; +} + +static inline void +query_releasename(ns_client_t *client, dns_name_t **namep) { + dns_name_t *name = *namep; + + /*% + * 'name' is no longer needed. Return it to our pool of temporary + * names. If it is using a name buffer, relinquish its exclusive + * rights on the buffer. + */ + + CTRACE("query_releasename"); + if (dns_name_hasbuffer(name)) { + INSIST((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) + != 0); + client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED; + } + dns_message_puttempname(client->message, namep); + CTRACE("query_releasename: done"); +} + +static inline dns_name_t * +query_newname(ns_client_t *client, isc_buffer_t *dbuf, + isc_buffer_t *nbuf) +{ + dns_name_t *name; + isc_region_t r; + isc_result_t result; + + REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) == 0); + + CTRACE("query_newname"); + name = NULL; + result = dns_message_gettempname(client->message, &name); + if (result != ISC_R_SUCCESS) { + CTRACE("query_newname: dns_message_gettempname failed: done"); + return (NULL); + } + isc_buffer_availableregion(dbuf, &r); + isc_buffer_init(nbuf, r.base, r.length); + dns_name_init(name, NULL); + dns_name_setbuffer(name, nbuf); + client->query.attributes |= NS_QUERYATTR_NAMEBUFUSED; + + CTRACE("query_newname: done"); + return (name); +} + +static inline dns_rdataset_t * +query_newrdataset(ns_client_t *client) { + dns_rdataset_t *rdataset; + isc_result_t result; + + CTRACE("query_newrdataset"); + rdataset = NULL; + result = dns_message_gettemprdataset(client->message, &rdataset); + if (result != ISC_R_SUCCESS) { + CTRACE("query_newrdataset: " + "dns_message_gettemprdataset failed: done"); + return (NULL); + } + dns_rdataset_init(rdataset); + + CTRACE("query_newrdataset: done"); + return (rdataset); +} + +static inline void +query_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp) { + dns_rdataset_t *rdataset = *rdatasetp; + + CTRACE("query_putrdataset"); + if (rdataset != NULL) { + if (dns_rdataset_isassociated(rdataset)) + dns_rdataset_disassociate(rdataset); + dns_message_puttemprdataset(client->message, rdatasetp); + } + CTRACE("query_putrdataset: done"); +} + + +static inline isc_result_t +query_newdbversion(ns_client_t *client, unsigned int n) { + unsigned int i; + ns_dbversion_t *dbversion; + + for (i = 0; i < n; i++) { + dbversion = isc_mem_get(client->mctx, sizeof(*dbversion)); + if (dbversion != NULL) { + dbversion->db = NULL; + dbversion->version = NULL; + ISC_LIST_INITANDAPPEND(client->query.freeversions, + dbversion, link); + } else { + /* + * We only return ISC_R_NOMEMORY if we couldn't + * allocate anything. + */ + if (i == 0) + return (ISC_R_NOMEMORY); + else + return (ISC_R_SUCCESS); + } + } + + return (ISC_R_SUCCESS); +} + +static inline ns_dbversion_t * +query_getdbversion(ns_client_t *client) { + isc_result_t result; + ns_dbversion_t *dbversion; + + if (ISC_LIST_EMPTY(client->query.freeversions)) { + result = query_newdbversion(client, 1); + if (result != ISC_R_SUCCESS) + return (NULL); + } + dbversion = ISC_LIST_HEAD(client->query.freeversions); + INSIST(dbversion != NULL); + ISC_LIST_UNLINK(client->query.freeversions, dbversion, link); + + return (dbversion); +} + +isc_result_t +ns_query_init(ns_client_t *client) { + isc_result_t result; + + ISC_LIST_INIT(client->query.namebufs); + ISC_LIST_INIT(client->query.activeversions); + ISC_LIST_INIT(client->query.freeversions); + client->query.restarts = 0; + client->query.timerset = ISC_FALSE; + client->query.qname = NULL; + result = isc_mutex_init(&client->query.fetchlock); + if (result != ISC_R_SUCCESS) + return (result); + client->query.fetch = NULL; + client->query.authdb = NULL; + client->query.authzone = NULL; + client->query.authdbset = ISC_FALSE; + client->query.isreferral = ISC_FALSE; + query_reset(client, ISC_FALSE); + result = query_newdbversion(client, 3); + if (result != ISC_R_SUCCESS) { + DESTROYLOCK(&client->query.fetchlock); + return (result); + } + result = query_newnamebuf(client); + if (result != ISC_R_SUCCESS) + query_freefreeversions(client, ISC_TRUE); + + return (result); +} + +static inline ns_dbversion_t * +query_findversion(ns_client_t *client, dns_db_t *db, + isc_boolean_t *newzonep) +{ + ns_dbversion_t *dbversion; + + /*% + * We may already have done a query related to this + * database. If so, we must be sure to make subsequent + * queries from the same version. + */ + for (dbversion = ISC_LIST_HEAD(client->query.activeversions); + dbversion != NULL; + dbversion = ISC_LIST_NEXT(dbversion, link)) { + if (dbversion->db == db) + break; + } + + if (dbversion == NULL) { + /* + * This is a new zone for this query. Add it to + * the active list. + */ + dbversion = query_getdbversion(client); + if (dbversion == NULL) + return (NULL); + dns_db_attach(db, &dbversion->db); + dns_db_currentversion(db, &dbversion->version); + dbversion->queryok = ISC_FALSE; + ISC_LIST_APPEND(client->query.activeversions, + dbversion, link); + *newzonep = ISC_TRUE; + } else + *newzonep = ISC_FALSE; + + return (dbversion); +} + +static inline isc_result_t +query_validatezonedb(ns_client_t *client, dns_name_t *name, + dns_rdatatype_t qtype, unsigned int options, + dns_zone_t *zone, dns_db_t *db, + dns_dbversion_t **versionp) +{ + isc_result_t result; + isc_boolean_t check_acl, new_zone; + dns_acl_t *queryacl; + ns_dbversion_t *dbversion; + + REQUIRE(zone != NULL); + REQUIRE(db != NULL); + + /* + * This limits our searching to the zone where the first name + * (the query target) was looked for. This prevents following + * CNAMES or DNAMES into other zones and prevents returning + * additional data from other zones. + */ + if (!client->view->additionalfromauth && + client->query.authdbset && + db != client->query.authdb) + goto refuse; + + /* + * If the zone has an ACL, we'll check it, otherwise + * we use the view's "allow-query" ACL. Each ACL is only checked + * once per query. + * + * Also, get the database version to use. + */ + + check_acl = ISC_TRUE; /* Keep compiler happy. */ + queryacl = NULL; + + /* + * Get the current version of this database. + */ + dbversion = query_findversion(client, db, &new_zone); + if (dbversion == NULL) { + result = DNS_R_SERVFAIL; + goto fail; + } + if (new_zone) { + check_acl = ISC_TRUE; + } else if (!dbversion->queryok) { + goto refuse; + } else { + check_acl = ISC_FALSE; + } + + queryacl = dns_zone_getqueryacl(zone); + if (queryacl == NULL) { + queryacl = client->view->queryacl; + if ((client->query.attributes & + NS_QUERYATTR_QUERYOKVALID) != 0) { + /* + * We've evaluated the view's queryacl already. If + * NS_QUERYATTR_QUERYOK is set, then the client is + * allowed to make queries, otherwise the query should + * be refused. + */ + check_acl = ISC_FALSE; + if ((client->query.attributes & + NS_QUERYATTR_QUERYOK) == 0) + goto refuse; + } else { + /* + * We haven't evaluated the view's queryacl yet. + */ + check_acl = ISC_TRUE; + } + } + + if (check_acl) { + isc_boolean_t log = ISC_TF((options & DNS_GETDB_NOLOG) == 0); + + result = ns_client_checkaclsilent(client, NULL, queryacl, + ISC_TRUE); + if (log) { + char msg[NS_CLIENT_ACLMSGSIZE("query")]; + if (result == ISC_R_SUCCESS) { + if (isc_log_wouldlog(ns_g_lctx, + ISC_LOG_DEBUG(3))) + { + ns_client_aclmsg("query", name, qtype, + client->view->rdclass, + msg, sizeof(msg)); + ns_client_log(client, + DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_QUERY, + ISC_LOG_DEBUG(3), + "%s approved", msg); + } + } else { + ns_client_aclmsg("query", name, qtype, + client->view->rdclass, + msg, sizeof(msg)); + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_QUERY, ISC_LOG_INFO, + "%s denied", msg); + } + } + + if (queryacl == client->view->queryacl) { + if (result == ISC_R_SUCCESS) { + /* + * We were allowed by the default + * "allow-query" ACL. Remember this so we + * don't have to check again. + */ + client->query.attributes |= + NS_QUERYATTR_QUERYOK; + } + /* + * We've now evaluated the view's query ACL, and + * the NS_QUERYATTR_QUERYOK attribute is now valid. + */ + client->query.attributes |= NS_QUERYATTR_QUERYOKVALID; + } + + if (result != ISC_R_SUCCESS) + goto refuse; + } + + /* Approved. */ + + /* + * Remember the result of the ACL check so we + * don't have to check again. + */ + dbversion->queryok = ISC_TRUE; + + /* Transfer ownership, if necessary. */ + if (versionp != NULL) + *versionp = dbversion->version; + + return (ISC_R_SUCCESS); + + refuse: + return (DNS_R_REFUSED); + + fail: + return (result); +} + +static inline isc_result_t +query_getzonedb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype, + unsigned int options, dns_zone_t **zonep, dns_db_t **dbp, + dns_dbversion_t **versionp) +{ + isc_result_t result; + unsigned int ztoptions; + dns_zone_t *zone = NULL; + dns_db_t *db = NULL; + isc_boolean_t partial = ISC_FALSE; + + REQUIRE(zonep != NULL && *zonep == NULL); + REQUIRE(dbp != NULL && *dbp == NULL); + + /*% + * Find a zone database to answer the query. + */ + ztoptions = ((options & DNS_GETDB_NOEXACT) != 0) ? + DNS_ZTFIND_NOEXACT : 0; + + result = dns_zt_find(client->view->zonetable, name, ztoptions, NULL, + &zone); + if (result == DNS_R_PARTIALMATCH) + partial = ISC_TRUE; + if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) + result = dns_zone_getdb(zone, &db); + + if (result != ISC_R_SUCCESS) + goto fail; + + result = query_validatezonedb(client, name, qtype, options, zone, db, + versionp); + + if (result != ISC_R_SUCCESS) + goto fail; + + /* Transfer ownership. */ + *zonep = zone; + *dbp = db; + + if (partial && (options & DNS_GETDB_PARTIAL) != 0) + return (DNS_R_PARTIALMATCH); + return (ISC_R_SUCCESS); + + fail: + if (zone != NULL) + dns_zone_detach(&zone); + if (db != NULL) + dns_db_detach(&db); + + return (result); +} + +static inline isc_result_t +query_getcachedb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype, + dns_db_t **dbp, unsigned int options) +{ + isc_result_t result; + isc_boolean_t check_acl; + dns_db_t *db = NULL; + + REQUIRE(dbp != NULL && *dbp == NULL); + + /*% + * Find a cache database to answer the query. + * This may fail with DNS_R_REFUSED if the client + * is not allowed to use the cache. + */ + + if (!USECACHE(client)) + return (DNS_R_REFUSED); + dns_db_attach(client->view->cachedb, &db); + + if ((client->query.attributes & + NS_QUERYATTR_QUERYOKVALID) != 0) { + /* + * We've evaluated the view's queryacl already. If + * NS_QUERYATTR_QUERYOK is set, then the client is + * allowed to make queries, otherwise the query should + * be refused. + */ + check_acl = ISC_FALSE; + if ((client->query.attributes & + NS_QUERYATTR_QUERYOK) == 0) + goto refuse; + } else { + /* + * We haven't evaluated the view's queryacl yet. + */ + check_acl = ISC_TRUE; + } + + if (check_acl) { + isc_boolean_t log = ISC_TF((options & DNS_GETDB_NOLOG) == 0); + char msg[NS_CLIENT_ACLMSGSIZE("query (cache)")]; + + result = ns_client_checkaclsilent(client, NULL, + client->view->queryacl, + ISC_TRUE); + if (result == ISC_R_SUCCESS) { + /* + * We were allowed by the default + * "allow-query" ACL. Remember this so we + * don't have to check again. + */ + client->query.attributes |= + NS_QUERYATTR_QUERYOK; + if (log && isc_log_wouldlog(ns_g_lctx, + ISC_LOG_DEBUG(3))) + { + ns_client_aclmsg("query (cache)", name, qtype, + client->view->rdclass, + msg, sizeof(msg)); + ns_client_log(client, + DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_QUERY, + ISC_LOG_DEBUG(3), + "%s approved", msg); + } + } else if (log) { + ns_client_aclmsg("query (cache)", name, qtype, + client->view->rdclass, msg, + sizeof(msg)); + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_QUERY, ISC_LOG_INFO, + "%s denied", msg); + } + /* + * We've now evaluated the view's query ACL, and + * the NS_QUERYATTR_QUERYOK attribute is now valid. + */ + client->query.attributes |= NS_QUERYATTR_QUERYOKVALID; + + if (result != ISC_R_SUCCESS) + goto refuse; + } + + /* Approved. */ + + /* Transfer ownership. */ + *dbp = db; + + return (ISC_R_SUCCESS); + + refuse: + result = DNS_R_REFUSED; + + if (db != NULL) + dns_db_detach(&db); + + return (result); +} + + +static inline isc_result_t +query_getdb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype, + unsigned int options, dns_zone_t **zonep, dns_db_t **dbp, + dns_dbversion_t **versionp, isc_boolean_t *is_zonep) +{ + isc_result_t result; + +#ifdef DLZ + isc_result_t tresult; + unsigned int namelabels; + unsigned int zonelabels; + dns_zone_t *zone = NULL; + dns_db_t *tdbp; + + REQUIRE(zonep != NULL && *zonep == NULL); + + tdbp = NULL; + + /* Calculate how many labels are in name. */ + namelabels = dns_name_countlabels(name); + zonelabels = 0; + + /* Try to find name in bind's standard database. */ + result = query_getzonedb(client, name, qtype, options, &zone, + dbp, versionp); + + /* See how many labels are in the zone's name. */ + if (result == ISC_R_SUCCESS && zone != NULL) + zonelabels = dns_name_countlabels(dns_zone_getorigin(zone)); + /* + * If # zone labels < # name labels, try to find an even better match + * Only try if a DLZ driver is loaded for this view + */ + if (zonelabels < namelabels && client->view->dlzdatabase != NULL) { + tresult = dns_dlzfindzone(client->view, name, + zonelabels, &tdbp); + /* If we successful, we found a better match. */ + if (tresult == ISC_R_SUCCESS) { + /* + * If the previous search returned a zone, detach it. + */ + if (zone != NULL) + dns_zone_detach(&zone); + + /* + * If the previous search returned a database, + * detach it. + */ + if (*dbp != NULL) + dns_db_detach(dbp); + + /* + * If the previous search returned a version, clear it. + */ + *versionp = NULL; + + /* + * Get our database version. + */ + dns_db_currentversion(tdbp, versionp); + + /* + * Be sure to return our database. + */ + *dbp = tdbp; + + /* + * We return a null zone, No stats for DLZ zones. + */ + zone = NULL; + result = tresult; + } + } +#else + result = query_getzonedb(client, name, qtype, options, + zonep, dbp, versionp); +#endif + + /* If successful, Transfer ownership of zone. */ + if (result == ISC_R_SUCCESS) { +#ifdef DLZ + *zonep = zone; +#endif + /* + * If neither attempt above succeeded, return the cache instead + */ + *is_zonep = ISC_TRUE; + } else if (result == ISC_R_NOTFOUND) { + result = query_getcachedb(client, name, qtype, dbp, options); + *is_zonep = ISC_FALSE; + } + return (result); +} + +static inline isc_boolean_t +query_isduplicate(ns_client_t *client, dns_name_t *name, + dns_rdatatype_t type, dns_name_t **mnamep) +{ + dns_section_t section; + dns_name_t *mname = NULL; + isc_result_t result; + + CTRACE("query_isduplicate"); + + for (section = DNS_SECTION_ANSWER; + section <= DNS_SECTION_ADDITIONAL; + section++) { + result = dns_message_findname(client->message, section, + name, type, 0, &mname, NULL); + if (result == ISC_R_SUCCESS) { + /* + * We've already got this RRset in the response. + */ + CTRACE("query_isduplicate: true: done"); + return (ISC_TRUE); + } else if (result == DNS_R_NXRRSET) { + /* + * The name exists, but the rdataset does not. + */ + if (section == DNS_SECTION_ADDITIONAL) + break; + } else + RUNTIME_CHECK(result == DNS_R_NXDOMAIN); + mname = NULL; + } + + /* + * If the dns_name_t we're looking up is already in the message, + * we don't want to trigger the caller's name replacement logic. + */ + if (name == mname) + mname = NULL; + + *mnamep = mname; + + CTRACE("query_isduplicate: false: done"); + return (ISC_FALSE); +} + +static isc_result_t +query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { + ns_client_t *client = arg; + isc_result_t result, eresult; + dns_dbnode_t *node; + dns_db_t *db; + dns_name_t *fname, *mname; + dns_rdataset_t *rdataset, *sigrdataset, *trdataset; + isc_buffer_t *dbuf; + isc_buffer_t b; + dns_dbversion_t *version; + isc_boolean_t added_something, need_addname; + dns_zone_t *zone; + dns_rdatatype_t type; + + REQUIRE(NS_CLIENT_VALID(client)); + REQUIRE(qtype != dns_rdatatype_any); + + if (!WANTDNSSEC(client) && dns_rdatatype_isdnssec(qtype)) + return (ISC_R_SUCCESS); + + CTRACE("query_addadditional"); + + /* + * Initialization. + */ + eresult = ISC_R_SUCCESS; + fname = NULL; + rdataset = NULL; + sigrdataset = NULL; + trdataset = NULL; + db = NULL; + version = NULL; + node = NULL; + added_something = ISC_FALSE; + need_addname = ISC_FALSE; + zone = NULL; + + /* + * We treat type A additional section processing as if it + * were "any address type" additional section processing. + * To avoid multiple lookups, we do an 'any' database + * lookup and iterate over the node. + */ + if (qtype == dns_rdatatype_a) + type = dns_rdatatype_any; + else + type = qtype; + + /* + * Get some resources. + */ + dbuf = query_getnamebuf(client); + if (dbuf == NULL) + goto cleanup; + fname = query_newname(client, dbuf, &b); + rdataset = query_newrdataset(client); + if (fname == NULL || rdataset == NULL) + goto cleanup; + if (WANTDNSSEC(client)) { + sigrdataset = query_newrdataset(client); + if (sigrdataset == NULL) + goto cleanup; + } + + /* + * Look for a zone database that might contain authoritative + * additional data. + */ + result = query_getzonedb(client, name, qtype, DNS_GETDB_NOLOG, + &zone, &db, &version); + if (result != ISC_R_SUCCESS) + goto try_cache; + + CTRACE("query_addadditional: db_find"); + + /* + * Since we are looking for authoritative data, we do not set + * the GLUEOK flag. Glue will be looked for later, but not + * necessarily in the same database. + */ + node = NULL; + result = dns_db_find(db, name, version, type, client->query.dboptions, + client->now, &node, fname, rdataset, + sigrdataset); + if (result == ISC_R_SUCCESS) + goto found; + + if (dns_rdataset_isassociated(rdataset)) + dns_rdataset_disassociate(rdataset); + if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) + dns_rdataset_disassociate(sigrdataset); + if (node != NULL) + dns_db_detachnode(db, &node); + version = NULL; + dns_db_detach(&db); + + /* + * No authoritative data was found. The cache is our next best bet. + */ + + try_cache: + result = query_getcachedb(client, name, qtype, &db, DNS_GETDB_NOLOG); + if (result != ISC_R_SUCCESS) + /* + * Most likely the client isn't allowed to query the cache. + */ + goto try_glue; + /* + * Attempt to validate glue. + */ + if (sigrdataset == NULL) { + sigrdataset = query_newrdataset(client); + if (sigrdataset == NULL) + goto cleanup; + } + result = dns_db_find(db, name, version, type, + client->query.dboptions | DNS_DBFIND_GLUEOK, + client->now, &node, fname, rdataset, + sigrdataset); + if (result == DNS_R_GLUE && + validate(client, db, fname, rdataset, sigrdataset)) + result = ISC_R_SUCCESS; + if (!WANTDNSSEC(client)) + query_putrdataset(client, &sigrdataset); + if (result == ISC_R_SUCCESS) + goto found; + + if (dns_rdataset_isassociated(rdataset)) + dns_rdataset_disassociate(rdataset); + if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) + dns_rdataset_disassociate(sigrdataset); + if (node != NULL) + dns_db_detachnode(db, &node); + dns_db_detach(&db); + + try_glue: + /* + * No cached data was found. Glue is our last chance. + * RFC1035 sayeth: + * + * NS records cause both the usual additional section + * processing to locate a type A record, and, when used + * in a referral, a special search of the zone in which + * they reside for glue information. + * + * This is the "special search". Note that we must search + * the zone where the NS record resides, not the zone it + * points to, and that we only do the search in the delegation + * case (identified by client->query.gluedb being set). + */ + + if (client->query.gluedb == NULL) + goto cleanup; + + /* + * Don't poison caches using the bailiwick protection model. + */ + if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb))) + goto cleanup; + + dns_db_attach(client->query.gluedb, &db); + result = dns_db_find(db, name, version, type, + client->query.dboptions | DNS_DBFIND_GLUEOK, + client->now, &node, fname, rdataset, + sigrdataset); + if (!(result == ISC_R_SUCCESS || + result == DNS_R_ZONECUT || + result == DNS_R_GLUE)) + goto cleanup; + + found: + /* + * We have found a potential additional data rdataset, or + * at least a node to iterate over. + */ + query_keepname(client, fname, dbuf); + + /* + * If we have an rdataset, add it to the additional data + * section. + */ + mname = NULL; + if (dns_rdataset_isassociated(rdataset) && + !query_isduplicate(client, fname, type, &mname)) { + if (mname != NULL) { + query_releasename(client, &fname); + fname = mname; + } else + need_addname = ISC_TRUE; + ISC_LIST_APPEND(fname->list, rdataset, link); + trdataset = rdataset; + rdataset = NULL; + added_something = ISC_TRUE; + /* + * Note: we only add SIGs if we've added the type they cover, + * so we do not need to check if the SIG rdataset is already + * in the response. + */ + if (sigrdataset != NULL && + dns_rdataset_isassociated(sigrdataset)) + { + ISC_LIST_APPEND(fname->list, sigrdataset, link); + sigrdataset = NULL; + } + } + + if (qtype == dns_rdatatype_a) { + /* + * We now go looking for A and AAAA records, along with + * their signatures. + * + * XXXRTH This code could be more efficient. + */ + if (rdataset != NULL) { + if (dns_rdataset_isassociated(rdataset)) + dns_rdataset_disassociate(rdataset); + } else { + rdataset = query_newrdataset(client); + if (rdataset == NULL) + goto addname; + } + if (sigrdataset != NULL) { + if (dns_rdataset_isassociated(sigrdataset)) + dns_rdataset_disassociate(sigrdataset); + } else if (WANTDNSSEC(client)) { + sigrdataset = query_newrdataset(client); + if (sigrdataset == NULL) + goto addname; + } + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_a, 0, + client->now, rdataset, + sigrdataset); + if (result == DNS_R_NCACHENXDOMAIN) + goto addname; + if (result == DNS_R_NCACHENXRRSET) { + dns_rdataset_disassociate(rdataset); + /* + * Negative cache entries don't have sigrdatasets. + */ + INSIST(sigrdataset == NULL || + ! dns_rdataset_isassociated(sigrdataset)); + } + if (result == ISC_R_SUCCESS) { + mname = NULL; + if (!query_isduplicate(client, fname, + dns_rdatatype_a, &mname)) { + if (mname != NULL) { + query_releasename(client, &fname); + fname = mname; + } else + need_addname = ISC_TRUE; + ISC_LIST_APPEND(fname->list, rdataset, link); + added_something = ISC_TRUE; + if (sigrdataset != NULL && + dns_rdataset_isassociated(sigrdataset)) + { + ISC_LIST_APPEND(fname->list, + sigrdataset, link); + sigrdataset = + query_newrdataset(client); + } + rdataset = query_newrdataset(client); + if (rdataset == NULL) + goto addname; + if (WANTDNSSEC(client) && sigrdataset == NULL) + goto addname; + } else { + dns_rdataset_disassociate(rdataset); + if (sigrdataset != NULL && + dns_rdataset_isassociated(sigrdataset)) + dns_rdataset_disassociate(sigrdataset); + } + } + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_aaaa, 0, + client->now, rdataset, + sigrdataset); + if (result == DNS_R_NCACHENXDOMAIN) + goto addname; + if (result == DNS_R_NCACHENXRRSET) { + dns_rdataset_disassociate(rdataset); + INSIST(sigrdataset == NULL || + ! dns_rdataset_isassociated(sigrdataset)); + } + if (result == ISC_R_SUCCESS) { + mname = NULL; + if (!query_isduplicate(client, fname, + dns_rdatatype_aaaa, &mname)) { + if (mname != NULL) { + query_releasename(client, &fname); + fname = mname; + } else + need_addname = ISC_TRUE; + ISC_LIST_APPEND(fname->list, rdataset, link); + added_something = ISC_TRUE; + if (sigrdataset != NULL && + dns_rdataset_isassociated(sigrdataset)) + { + ISC_LIST_APPEND(fname->list, + sigrdataset, link); + sigrdataset = NULL; + } + rdataset = NULL; + } + } + } + + addname: + CTRACE("query_addadditional: addname"); + /* + * If we haven't added anything, then we're done. + */ + if (!added_something) + goto cleanup; + + /* + * We may have added our rdatasets to an existing name, if so, then + * need_addname will be ISC_FALSE. Whether we used an existing name + * or a new one, we must set fname to NULL to prevent cleanup. + */ + if (need_addname) + dns_message_addname(client->message, fname, + DNS_SECTION_ADDITIONAL); + fname = NULL; + + /* + * In a few cases, we want to add additional data for additional + * data. It's simpler to just deal with special cases here than + * to try to create a general purpose mechanism and allow the + * rdata implementations to do it themselves. + * + * This involves recursion, but the depth is limited. The + * most complex case is adding a SRV rdataset, which involves + * recursing to add address records, which in turn can cause + * recursion to add KEYs. + */ + if (type == dns_rdatatype_srv && trdataset != NULL) { + /* + * If we're adding SRV records to the additional data + * section, it's helpful if we add the SRV additional data + * as well. + */ + eresult = dns_rdataset_additionaldata(trdataset, + query_addadditional, + client); + } + + cleanup: + CTRACE("query_addadditional: cleanup"); + query_putrdataset(client, &rdataset); + if (sigrdataset != NULL) + query_putrdataset(client, &sigrdataset); + if (fname != NULL) + query_releasename(client, &fname); + if (node != NULL) + dns_db_detachnode(db, &node); + if (db != NULL) + dns_db_detach(&db); + if (zone != NULL) + dns_zone_detach(&zone); + + CTRACE("query_addadditional: done"); + return (eresult); +} + +static inline void +query_discardcache(ns_client_t *client, dns_rdataset_t *rdataset_base, + dns_rdatasetadditional_t additionaltype, + dns_rdatatype_t type, dns_zone_t **zonep, dns_db_t **dbp, + dns_dbversion_t **versionp, dns_dbnode_t **nodep, + dns_name_t *fname) +{ + dns_rdataset_t *rdataset; + + while ((rdataset = ISC_LIST_HEAD(fname->list)) != NULL) { + ISC_LIST_UNLINK(fname->list, rdataset, link); + query_putrdataset(client, &rdataset); + } + if (*versionp != NULL) + dns_db_closeversion(*dbp, versionp, ISC_FALSE); + if (*nodep != NULL) + dns_db_detachnode(*dbp, nodep); + if (*dbp != NULL) + dns_db_detach(dbp); + if (*zonep != NULL) + dns_zone_detach(zonep); + (void)dns_rdataset_putadditional(client->view->acache, rdataset_base, + additionaltype, type); +} + +static inline isc_result_t +query_iscachevalid(dns_zone_t *zone, dns_db_t *db, dns_db_t *db0, + dns_dbversion_t *version) +{ + isc_result_t result = ISC_R_SUCCESS; + dns_dbversion_t *version_current = NULL; + dns_db_t *db_current = db0; + + if (db_current == NULL) { + result = dns_zone_getdb(zone, &db_current); + if (result != ISC_R_SUCCESS) + return (result); + } + dns_db_currentversion(db_current, &version_current); + if (db_current != db || version_current != version) { + result = ISC_R_FAILURE; + goto cleanup; + } + + cleanup: + dns_db_closeversion(db_current, &version_current, ISC_FALSE); + if (db0 == NULL && db_current != NULL) + dns_db_detach(&db_current); + + return (result); +} + +static isc_result_t +query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { + client_additionalctx_t *additionalctx = arg; + dns_rdataset_t *rdataset_base; + ns_client_t *client; + isc_result_t result, eresult; + dns_dbnode_t *node, *cnode; + dns_db_t *db, *cdb; + dns_name_t *fname, *mname0, cfname; + dns_rdataset_t *rdataset, *sigrdataset; + dns_rdataset_t *crdataset, *crdataset_next; + isc_buffer_t *dbuf; + isc_buffer_t b; + dns_dbversion_t *version, *cversion; + isc_boolean_t added_something, need_addname, needadditionalcache; + isc_boolean_t need_sigrrset; + dns_zone_t *zone; + dns_rdatatype_t type; + dns_rdatasetadditional_t additionaltype; + + if (qtype != dns_rdatatype_a) { + /* + * This function is optimized for "address" types. For other + * types, use a generic routine. + * XXX: ideally, this function should be generic enough. + */ + return (query_addadditional(additionalctx->client, + name, qtype)); + } + + /* + * Initialization. + */ + rdataset_base = additionalctx->rdataset; + client = additionalctx->client; + REQUIRE(NS_CLIENT_VALID(client)); + eresult = ISC_R_SUCCESS; + fname = NULL; + rdataset = NULL; + sigrdataset = NULL; + db = NULL; + cdb = NULL; + version = NULL; + cversion = NULL; + node = NULL; + cnode = NULL; + added_something = ISC_FALSE; + need_addname = ISC_FALSE; + zone = NULL; + needadditionalcache = ISC_FALSE; + additionaltype = dns_rdatasetadditional_fromauth; + dns_name_init(&cfname, NULL); + + CTRACE("query_addadditional2"); + + /* + * We treat type A additional section processing as if it + * were "any address type" additional section processing. + * To avoid multiple lookups, we do an 'any' database + * lookup and iterate over the node. + * XXXJT: this approach can cause a suboptimal result when the cache + * DB only has partial address types and the glue DB has remaining + * ones. + */ + type = dns_rdatatype_any; + + /* + * Get some resources. + */ + dbuf = query_getnamebuf(client); + if (dbuf == NULL) + goto cleanup; + fname = query_newname(client, dbuf, &b); + if (fname == NULL) + goto cleanup; + dns_name_setbuffer(&cfname, &b); /* share the buffer */ + + /* Check additional cache */ + result = dns_rdataset_getadditional(rdataset_base, additionaltype, + type, client->view->acache, &zone, + &cdb, &cversion, &cnode, &cfname, + client->message, client->now); + if (result != ISC_R_SUCCESS) + goto findauthdb; + if (zone == NULL) { + CTRACE("query_addadditional2: auth zone not found"); + goto try_cache; + } + + /* Is the cached DB up-to-date? */ + result = query_iscachevalid(zone, cdb, NULL, cversion); + if (result != ISC_R_SUCCESS) { + CTRACE("query_addadditional2: old auth additional cache"); + query_discardcache(client, rdataset_base, additionaltype, + type, &zone, &cdb, &cversion, &cnode, + &cfname); + goto findauthdb; + } + + if (cnode == NULL) { + /* + * We have a negative cache. We don't have to check the zone + * ACL, since the result (not using this zone) would be same + * regardless of the result. + */ + CTRACE("query_addadditional2: negative auth additional cache"); + dns_db_closeversion(cdb, &cversion, ISC_FALSE); + dns_db_detach(&cdb); + dns_zone_detach(&zone); + goto try_cache; + } + + result = query_validatezonedb(client, name, qtype, DNS_GETDB_NOLOG, + zone, cdb, NULL); + if (result != ISC_R_SUCCESS) { + query_discardcache(client, rdataset_base, additionaltype, + type, &zone, &cdb, &cversion, &cnode, + &cfname); + goto try_cache; + } + + /* We've got an active cache. */ + CTRACE("query_addadditional2: auth additional cache"); + dns_db_closeversion(cdb, &cversion, ISC_FALSE); + db = cdb; + node = cnode; + dns_name_clone(&cfname, fname); + query_keepname(client, fname, dbuf); + goto foundcache; + + /* + * Look for a zone database that might contain authoritative + * additional data. + */ + findauthdb: + result = query_getzonedb(client, name, qtype, DNS_GETDB_NOLOG, + &zone, &db, &version); + if (result != ISC_R_SUCCESS) { + /* Cache the negative result */ + (void)dns_rdataset_setadditional(rdataset_base, additionaltype, + type, client->view->acache, + NULL, NULL, NULL, NULL, + NULL); + goto try_cache; + } + + CTRACE("query_addadditional2: db_find"); + + /* + * Since we are looking for authoritative data, we do not set + * the GLUEOK flag. Glue will be looked for later, but not + * necessarily in the same database. + */ + node = NULL; + result = dns_db_find(db, name, version, type, client->query.dboptions, + client->now, &node, fname, NULL, NULL); + if (result == ISC_R_SUCCESS) + goto found; + + /* Cache the negative result */ + (void)dns_rdataset_setadditional(rdataset_base, additionaltype, + type, client->view->acache, zone, db, + version, NULL, fname); + + if (node != NULL) + dns_db_detachnode(db, &node); + version = NULL; + dns_db_detach(&db); + + /* + * No authoritative data was found. The cache is our next best bet. + */ + + try_cache: + additionaltype = dns_rdatasetadditional_fromcache; + result = query_getcachedb(client, name, qtype, &db, DNS_GETDB_NOLOG); + if (result != ISC_R_SUCCESS) + /* + * Most likely the client isn't allowed to query the cache. + */ + goto try_glue; + + result = dns_db_find(db, name, version, type, + client->query.dboptions | DNS_DBFIND_GLUEOK, + client->now, &node, fname, NULL, NULL); + if (result == ISC_R_SUCCESS) + goto found; + + if (node != NULL) + dns_db_detachnode(db, &node); + dns_db_detach(&db); + + try_glue: + /* + * No cached data was found. Glue is our last chance. + * RFC1035 sayeth: + * + * NS records cause both the usual additional section + * processing to locate a type A record, and, when used + * in a referral, a special search of the zone in which + * they reside for glue information. + * + * This is the "special search". Note that we must search + * the zone where the NS record resides, not the zone it + * points to, and that we only do the search in the delegation + * case (identified by client->query.gluedb being set). + */ + if (client->query.gluedb == NULL) + goto cleanup; + + /* + * Don't poison caches using the bailiwick protection model. + */ + if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb))) + goto cleanup; + + /* Check additional cache */ + additionaltype = dns_rdatasetadditional_fromglue; + result = dns_rdataset_getadditional(rdataset_base, additionaltype, + type, client->view->acache, NULL, + &cdb, &cversion, &cnode, &cfname, + client->message, client->now); + if (result != ISC_R_SUCCESS) + goto findglue; + + result = query_iscachevalid(zone, cdb, client->query.gluedb, cversion); + if (result != ISC_R_SUCCESS) { + CTRACE("query_addadditional2: old glue additional cache"); + query_discardcache(client, rdataset_base, additionaltype, + type, &zone, &cdb, &cversion, &cnode, + &cfname); + goto findglue; + } + + if (cnode == NULL) { + /* We have a negative cache. */ + CTRACE("query_addadditional2: negative glue additional cache"); + dns_db_closeversion(cdb, &cversion, ISC_FALSE); + dns_db_detach(&cdb); + goto cleanup; + } + + /* Cache hit. */ + CTRACE("query_addadditional2: glue additional cache"); + dns_db_closeversion(cdb, &cversion, ISC_FALSE); + db = cdb; + node = cnode; + dns_name_clone(&cfname, fname); + query_keepname(client, fname, dbuf); + goto foundcache; + + findglue: + dns_db_attach(client->query.gluedb, &db); + result = dns_db_find(db, name, version, type, + client->query.dboptions | DNS_DBFIND_GLUEOK, + client->now, &node, fname, NULL, NULL); + if (!(result == ISC_R_SUCCESS || + result == DNS_R_ZONECUT || + result == DNS_R_GLUE)) { + /* cache the negative result */ + (void)dns_rdataset_setadditional(rdataset_base, additionaltype, + type, client->view->acache, + NULL, db, version, NULL, + fname); + goto cleanup; + } + + found: + /* + * We have found a DB node to iterate over from a DB. + * We are going to look for address RRsets (i.e., A and AAAA) in the DB + * node we've just found. We'll then store the complete information + * in the additional data cache. + */ + dns_name_clone(fname, &cfname); + query_keepname(client, fname, dbuf); + needadditionalcache = ISC_TRUE; + + rdataset = query_newrdataset(client); + if (rdataset == NULL) + goto cleanup; + + sigrdataset = query_newrdataset(client); + if (sigrdataset == NULL) + goto cleanup; + + /* + * Find A RRset with sig RRset. Even if we don't find a sig RRset + * for a client using DNSSEC, we'll continue the process to make a + * complete list to be cached. However, we need to cancel the + * caching when something unexpected happens, in order to avoid + * caching incomplete information. + */ + result = dns_db_findrdataset(db, node, version, dns_rdatatype_a, 0, + client->now, rdataset, sigrdataset); + /* + * If we can't promote glue/pending from the cache to secure + * then drop it. + */ + if (result == ISC_R_SUCCESS && + additionaltype == dns_rdatasetadditional_fromcache && + (rdataset->trust == dns_trust_pending || + rdataset->trust == dns_trust_glue) && + !validate(client, db, fname, rdataset, sigrdataset)) { + dns_rdataset_disassociate(rdataset); + if (dns_rdataset_isassociated(sigrdataset)) + dns_rdataset_disassociate(sigrdataset); + result = ISC_R_NOTFOUND; + } + if (result == DNS_R_NCACHENXDOMAIN) + goto setcache; + if (result == DNS_R_NCACHENXRRSET) { + dns_rdataset_disassociate(rdataset); + /* + * Negative cache entries don't have sigrdatasets. + */ + INSIST(! dns_rdataset_isassociated(sigrdataset)); + } + if (result == ISC_R_SUCCESS) { + /* Remember the result as a cache */ + ISC_LIST_APPEND(cfname.list, rdataset, link); + if (dns_rdataset_isassociated(sigrdataset)) { + ISC_LIST_APPEND(cfname.list, sigrdataset, link); + sigrdataset = query_newrdataset(client); + } + rdataset = query_newrdataset(client); + if (sigrdataset == NULL || rdataset == NULL) { + /* do not cache incomplete information */ + goto foundcache; + } + } + + /* Find AAAA RRset with sig RRset */ + result = dns_db_findrdataset(db, node, version, dns_rdatatype_aaaa, + 0, client->now, rdataset, sigrdataset); + /* + * If we can't promote glue/pending from the cache to secure + * then drop it. + */ + if (result == ISC_R_SUCCESS && + additionaltype == dns_rdatasetadditional_fromcache && + (rdataset->trust == dns_trust_pending || + rdataset->trust == dns_trust_glue) && + !validate(client, db, fname, rdataset, sigrdataset)) { + dns_rdataset_disassociate(rdataset); + if (dns_rdataset_isassociated(sigrdataset)) + dns_rdataset_disassociate(sigrdataset); + result = ISC_R_NOTFOUND; + } + if (result == ISC_R_SUCCESS) { + ISC_LIST_APPEND(cfname.list, rdataset, link); + rdataset = NULL; + if (dns_rdataset_isassociated(sigrdataset)) { + ISC_LIST_APPEND(cfname.list, sigrdataset, link); + sigrdataset = NULL; + } + } + + setcache: + /* + * Set the new result in the cache if required. We do not support + * caching additional data from a cache DB. + */ + if (needadditionalcache == ISC_TRUE && + (additionaltype == dns_rdatasetadditional_fromauth || + additionaltype == dns_rdatasetadditional_fromglue)) { + (void)dns_rdataset_setadditional(rdataset_base, additionaltype, + type, client->view->acache, + zone, db, version, node, + &cfname); + } + + foundcache: + need_sigrrset = ISC_FALSE; + mname0 = NULL; + for (crdataset = ISC_LIST_HEAD(cfname.list); + crdataset != NULL; + crdataset = crdataset_next) { + dns_name_t *mname; + + crdataset_next = ISC_LIST_NEXT(crdataset, link); + + mname = NULL; + if (crdataset->type == dns_rdatatype_a || + crdataset->type == dns_rdatatype_aaaa) { + if (!query_isduplicate(client, fname, crdataset->type, + &mname)) { + if (mname != NULL) { + /* + * A different type of this name is + * already stored in the additional + * section. We'll reuse the name. + * Note that this should happen at most + * once. Otherwise, fname->link could + * leak below. + */ + INSIST(mname0 == NULL); + + query_releasename(client, &fname); + fname = mname; + mname0 = mname; + } else + need_addname = ISC_TRUE; + ISC_LIST_UNLINK(cfname.list, crdataset, link); + ISC_LIST_APPEND(fname->list, crdataset, link); + added_something = ISC_TRUE; + need_sigrrset = ISC_TRUE; + } else + need_sigrrset = ISC_FALSE; + } else if (crdataset->type == dns_rdatatype_rrsig && + need_sigrrset && WANTDNSSEC(client)) { + ISC_LIST_UNLINK(cfname.list, crdataset, link); + ISC_LIST_APPEND(fname->list, crdataset, link); + added_something = ISC_TRUE; /* just in case */ + need_sigrrset = ISC_FALSE; + } + } + + CTRACE("query_addadditional2: addname"); + + /* + * If we haven't added anything, then we're done. + */ + if (!added_something) + goto cleanup; + + /* + * We may have added our rdatasets to an existing name, if so, then + * need_addname will be ISC_FALSE. Whether we used an existing name + * or a new one, we must set fname to NULL to prevent cleanup. + */ + if (need_addname) + dns_message_addname(client->message, fname, + DNS_SECTION_ADDITIONAL); + fname = NULL; + + cleanup: + CTRACE("query_addadditional2: cleanup"); + + if (rdataset != NULL) + query_putrdataset(client, &rdataset); + if (sigrdataset != NULL) + query_putrdataset(client, &sigrdataset); + while ((crdataset = ISC_LIST_HEAD(cfname.list)) != NULL) { + ISC_LIST_UNLINK(cfname.list, crdataset, link); + query_putrdataset(client, &crdataset); + } + if (fname != NULL) + query_releasename(client, &fname); + if (node != NULL) + dns_db_detachnode(db, &node); + if (db != NULL) + dns_db_detach(&db); + if (zone != NULL) + dns_zone_detach(&zone); + + CTRACE("query_addadditional2: done"); + return (eresult); +} + +static inline void +query_addrdataset(ns_client_t *client, dns_name_t *fname, + dns_rdataset_t *rdataset) +{ + client_additionalctx_t additionalctx; + + /* + * Add 'rdataset' and any pertinent additional data to + * 'fname', a name in the response message for 'client'. + */ + + CTRACE("query_addrdataset"); + + ISC_LIST_APPEND(fname->list, rdataset, link); + + if (client->view->order != NULL) + rdataset->attributes |= dns_order_find(client->view->order, + fname, rdataset->type, + rdataset->rdclass); + rdataset->attributes |= DNS_RDATASETATTR_LOADORDER; + + if (NOADDITIONAL(client)) + return; + + /* + * Add additional data. + * + * We don't care if dns_rdataset_additionaldata() fails. + */ + additionalctx.client = client; + additionalctx.rdataset = rdataset; + (void)dns_rdataset_additionaldata(rdataset, query_addadditional2, + &additionalctx); + CTRACE("query_addrdataset: done"); +} + +static void +query_addrrset(ns_client_t *client, dns_name_t **namep, + dns_rdataset_t **rdatasetp, dns_rdataset_t **sigrdatasetp, + isc_buffer_t *dbuf, dns_section_t section) +{ + dns_name_t *name, *mname; + dns_rdataset_t *rdataset, *mrdataset, *sigrdataset; + isc_result_t result; + + /*% + * To the current response for 'client', add the answer RRset + * '*rdatasetp' and an optional signature set '*sigrdatasetp', with + * owner name '*namep', to section 'section', unless they are + * already there. Also add any pertinent additional data. + * + * If 'dbuf' is not NULL, then '*namep' is the name whose data is + * stored in 'dbuf'. In this case, query_addrrset() guarantees that + * when it returns the name will either have been kept or released. + */ + CTRACE("query_addrrset"); + name = *namep; + rdataset = *rdatasetp; + if (sigrdatasetp != NULL) + sigrdataset = *sigrdatasetp; + else + sigrdataset = NULL; + mname = NULL; + mrdataset = NULL; + result = dns_message_findname(client->message, section, + name, rdataset->type, rdataset->covers, + &mname, &mrdataset); + if (result == ISC_R_SUCCESS) { + /* + * We've already got an RRset of the given name and type. + * There's nothing else to do; + */ + CTRACE("query_addrrset: dns_message_findname succeeded: done"); + if (dbuf != NULL) + query_releasename(client, namep); + return; + } else if (result == DNS_R_NXDOMAIN) { + /* + * The name doesn't exist. + */ + if (dbuf != NULL) + query_keepname(client, name, dbuf); + dns_message_addname(client->message, name, section); + *namep = NULL; + mname = name; + } else { + RUNTIME_CHECK(result == DNS_R_NXRRSET); + if (dbuf != NULL) + query_releasename(client, namep); + } + + if (rdataset->trust != dns_trust_secure && + (section == DNS_SECTION_ANSWER || + section == DNS_SECTION_AUTHORITY)) + client->query.attributes &= ~NS_QUERYATTR_SECURE; + /* + * Note: we only add SIGs if we've added the type they cover, so + * we do not need to check if the SIG rdataset is already in the + * response. + */ + query_addrdataset(client, mname, rdataset); + *rdatasetp = NULL; + if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) { + /* + * We have a signature. Add it to the response. + */ + ISC_LIST_APPEND(mname->list, sigrdataset, link); + *sigrdatasetp = NULL; + } + CTRACE("query_addrrset: done"); +} + +static inline isc_result_t +query_addsoa(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version, + isc_boolean_t zero_ttl) +{ + dns_name_t *name; + dns_dbnode_t *node; + isc_result_t result, eresult; + dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL; + dns_rdataset_t **sigrdatasetp = NULL; + + CTRACE("query_addsoa"); + /* + * Initialization. + */ + eresult = ISC_R_SUCCESS; + name = NULL; + rdataset = NULL; + node = NULL; + + /* + * Get resources and make 'name' be the database origin. + */ + result = dns_message_gettempname(client->message, &name); + if (result != ISC_R_SUCCESS) + return (result); + dns_name_init(name, NULL); + dns_name_clone(dns_db_origin(db), name); + rdataset = query_newrdataset(client); + if (rdataset == NULL) { + eresult = DNS_R_SERVFAIL; + goto cleanup; + } + if (WANTDNSSEC(client)) { + sigrdataset = query_newrdataset(client); + if (sigrdataset == NULL) { + eresult = DNS_R_SERVFAIL; + goto cleanup; + } + } + + /* + * Find the SOA. + */ + result = dns_db_getoriginnode(db, &node); + if (result == ISC_R_SUCCESS) { + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_soa, + 0, client->now, rdataset, + sigrdataset); + } else { + dns_fixedname_t foundname; + dns_name_t *fname; + + dns_fixedname_init(&foundname); + fname = dns_fixedname_name(&foundname); + + result = dns_db_find(db, name, version, dns_rdatatype_soa, + client->query.dboptions, 0, &node, + fname, rdataset, sigrdataset); + } + if (result != ISC_R_SUCCESS) { + /* + * This is bad. We tried to get the SOA RR at the zone top + * and it didn't work! + */ + eresult = DNS_R_SERVFAIL; + } else { + /* + * Extract the SOA MINIMUM. + */ + dns_rdata_soa_t soa; + dns_rdata_t rdata = DNS_RDATA_INIT; + result = dns_rdataset_first(rdataset); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + dns_rdataset_current(rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &soa, NULL); + if (result != ISC_R_SUCCESS) + goto cleanup; + + if (zero_ttl) { + rdataset->ttl = 0; + if (sigrdataset != NULL) + sigrdataset->ttl = 0; + } + + /* + * Add the SOA and its SIG to the response, with the + * TTLs adjusted per RFC2308 section 3. + */ + if (rdataset->ttl > soa.minimum) + rdataset->ttl = soa.minimum; + if (sigrdataset != NULL && sigrdataset->ttl > soa.minimum) + sigrdataset->ttl = soa.minimum; + + if (sigrdataset != NULL) + sigrdatasetp = &sigrdataset; + else + sigrdatasetp = NULL; + query_addrrset(client, &name, &rdataset, sigrdatasetp, NULL, + DNS_SECTION_AUTHORITY); + } + + cleanup: + query_putrdataset(client, &rdataset); + if (sigrdataset != NULL) + query_putrdataset(client, &sigrdataset); + if (name != NULL) + query_releasename(client, &name); + if (node != NULL) + dns_db_detachnode(db, &node); + + return (eresult); +} + +static inline isc_result_t +query_addns(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version) { + dns_name_t *name, *fname; + dns_dbnode_t *node; + isc_result_t result, eresult; + dns_fixedname_t foundname; + dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL; + dns_rdataset_t **sigrdatasetp = NULL; + + CTRACE("query_addns"); + /* + * Initialization. + */ + eresult = ISC_R_SUCCESS; + name = NULL; + rdataset = NULL; + node = NULL; + dns_fixedname_init(&foundname); + fname = dns_fixedname_name(&foundname); + + /* + * Get resources and make 'name' be the database origin. + */ + result = dns_message_gettempname(client->message, &name); + if (result != ISC_R_SUCCESS) { + CTRACE("query_addns: dns_message_gettempname failed: done"); + return (result); + } + dns_name_init(name, NULL); + dns_name_clone(dns_db_origin(db), name); + rdataset = query_newrdataset(client); + if (rdataset == NULL) { + CTRACE("query_addns: query_newrdataset failed"); + eresult = DNS_R_SERVFAIL; + goto cleanup; + } + if (WANTDNSSEC(client)) { + sigrdataset = query_newrdataset(client); + if (sigrdataset == NULL) { + CTRACE("query_addns: query_newrdataset failed"); + eresult = DNS_R_SERVFAIL; + goto cleanup; + } + } + + /* + * Find the NS rdataset. + */ + result = dns_db_getoriginnode(db, &node); + if (result == ISC_R_SUCCESS) { + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_ns, + 0, client->now, rdataset, + sigrdataset); + } else { + CTRACE("query_addns: calling dns_db_find"); + result = dns_db_find(db, name, NULL, dns_rdatatype_ns, + client->query.dboptions, 0, &node, + fname, rdataset, sigrdataset); + CTRACE("query_addns: dns_db_find complete"); + } + if (result != ISC_R_SUCCESS) { + CTRACE("query_addns: " + "dns_db_findrdataset or dns_db_find failed"); + /* + * This is bad. We tried to get the NS rdataset at the zone + * top and it didn't work! + */ + eresult = DNS_R_SERVFAIL; + } else { + if (sigrdataset != NULL) + sigrdatasetp = &sigrdataset; + else + sigrdatasetp = NULL; + query_addrrset(client, &name, &rdataset, sigrdatasetp, NULL, + DNS_SECTION_AUTHORITY); + } + + cleanup: + CTRACE("query_addns: cleanup"); + query_putrdataset(client, &rdataset); + if (sigrdataset != NULL) + query_putrdataset(client, &sigrdataset); + if (name != NULL) + query_releasename(client, &name); + if (node != NULL) + dns_db_detachnode(db, &node); + + CTRACE("query_addns: done"); + return (eresult); +} + +static inline isc_result_t +query_addcnamelike(ns_client_t *client, dns_name_t *qname, dns_name_t *tname, + dns_trust_t trust, dns_name_t **anamep, dns_rdatatype_t type) +{ + dns_rdataset_t *rdataset; + dns_rdatalist_t *rdatalist; + dns_rdata_t *rdata; + isc_result_t result; + isc_region_t r; + + /* + * We assume the name data referred to by tname won't go away. + */ + + REQUIRE(anamep != NULL); + + rdatalist = NULL; + result = dns_message_gettemprdatalist(client->message, &rdatalist); + if (result != ISC_R_SUCCESS) + return (result); + rdata = NULL; + result = dns_message_gettemprdata(client->message, &rdata); + if (result != ISC_R_SUCCESS) + return (result); + rdataset = NULL; + result = dns_message_gettemprdataset(client->message, &rdataset); + if (result != ISC_R_SUCCESS) + return (result); + dns_rdataset_init(rdataset); + result = dns_name_dup(qname, client->mctx, *anamep); + if (result != ISC_R_SUCCESS) { + dns_message_puttemprdataset(client->message, &rdataset); + return (result); + } + + rdatalist->type = type; + rdatalist->covers = 0; + rdatalist->rdclass = client->message->rdclass; + rdatalist->ttl = 0; + + dns_name_toregion(tname, &r); + rdata->data = r.base; + rdata->length = r.length; + rdata->rdclass = client->message->rdclass; + rdata->type = type; + + ISC_LIST_INIT(rdatalist->rdata); + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) + == ISC_R_SUCCESS); + rdataset->trust = trust; + + query_addrrset(client, anamep, &rdataset, NULL, NULL, + DNS_SECTION_ANSWER); + + if (rdataset != NULL) { + if (dns_rdataset_isassociated(rdataset)) + dns_rdataset_disassociate(rdataset); + dns_message_puttemprdataset(client->message, &rdataset); + } + + return (ISC_R_SUCCESS); +} + +/* + * Mark the RRsets as secure. Update the cache (db) to reflect the + * change in trust level. + */ +static void +mark_secure(ns_client_t *client, dns_db_t *db, dns_name_t *name, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) +{ + isc_result_t result; + dns_dbnode_t *node = NULL; + + rdataset->trust = dns_trust_secure; + sigrdataset->trust = dns_trust_secure; + + /* + * Save the updated secure state. Ignore failures. + */ + result = dns_db_findnode(db, name, ISC_TRUE, &node); + if (result != ISC_R_SUCCESS) + return; + (void)dns_db_addrdataset(db, node, NULL, client->now, rdataset, + 0, NULL); + (void)dns_db_addrdataset(db, node, NULL, client->now, sigrdataset, + 0, NULL); + dns_db_detachnode(db, &node); +} + +/* + * Find the secure key that corresponds to rrsig. + * Note: 'keyrdataset' maintains state between successive calls, + * there may be multiple keys with the same keyid. + * Return ISC_FALSE if we have exhausted all the possible keys. + */ +static isc_boolean_t +get_key(ns_client_t *client, dns_db_t *db, dns_rdata_rrsig_t *rrsig, + dns_rdataset_t *keyrdataset, dst_key_t **keyp) +{ + isc_result_t result; + dns_dbnode_t *node = NULL; + isc_boolean_t secure = ISC_FALSE; + + if (!dns_rdataset_isassociated(keyrdataset)) { + result = dns_db_findnode(db, &rrsig->signer, ISC_FALSE, &node); + if (result != ISC_R_SUCCESS) + return (ISC_FALSE); + + result = dns_db_findrdataset(db, node, NULL, + dns_rdatatype_dnskey, 0, + client->now, keyrdataset, NULL); + dns_db_detachnode(db, &node); + if (result != ISC_R_SUCCESS) + return (ISC_FALSE); + + if (keyrdataset->trust != dns_trust_secure) + return (ISC_FALSE); + + result = dns_rdataset_first(keyrdataset); + } else + result = dns_rdataset_next(keyrdataset); + + for ( ; result == ISC_R_SUCCESS; + result = dns_rdataset_next(keyrdataset)) { + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_buffer_t b; + + dns_rdataset_current(keyrdataset, &rdata); + isc_buffer_init(&b, rdata.data, rdata.length); + isc_buffer_add(&b, rdata.length); + result = dst_key_fromdns(&rrsig->signer, rdata.rdclass, &b, + client->mctx, keyp); + if (result != ISC_R_SUCCESS) + continue; + if (rrsig->algorithm == (dns_secalg_t)dst_key_alg(*keyp) && + rrsig->keyid == (dns_keytag_t)dst_key_id(*keyp) && + dst_key_iszonekey(*keyp)) { + secure = ISC_TRUE; + break; + } + dst_key_free(keyp); + } + return (secure); +} + +static isc_boolean_t +verify(dst_key_t *key, dns_name_t *name, dns_rdataset_t *rdataset, + dns_rdata_t *rdata, isc_mem_t *mctx, isc_boolean_t acceptexpired) +{ + isc_result_t result; + dns_fixedname_t fixed; + isc_boolean_t ignore = ISC_FALSE; + + dns_fixedname_init(&fixed); + +again: + result = dns_dnssec_verify2(name, rdataset, key, ignore, mctx, + rdata, NULL); + if (result == DNS_R_SIGEXPIRED && acceptexpired) { + ignore = ISC_TRUE; + goto again; + } + if (result == ISC_R_SUCCESS || result == DNS_R_FROMWILDCARD) + return (ISC_TRUE); + return (ISC_FALSE); +} + +/* + * Validate the rdataset if possible with available records. + */ +static isc_boolean_t +validate(ns_client_t *client, dns_db_t *db, dns_name_t *name, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) +{ + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_rrsig_t rrsig; + dst_key_t *key = NULL; + dns_rdataset_t keyrdataset; + + if (sigrdataset == NULL || !dns_rdataset_isassociated(sigrdataset)) + return (ISC_FALSE); + + for (result = dns_rdataset_first(sigrdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(sigrdataset)) { + + dns_rdata_reset(&rdata); + dns_rdataset_current(sigrdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &rrsig, NULL); + if (result != ISC_R_SUCCESS) + return (ISC_FALSE); + if (!dns_resolver_algorithm_supported(client->view->resolver, + name, rrsig.algorithm)) + continue; + if (!dns_name_issubdomain(name, &rrsig.signer)) + continue; + dns_rdataset_init(&keyrdataset); + do { + if (!get_key(client, db, &rrsig, &keyrdataset, &key)) + break; + if (verify(key, name, rdataset, &rdata, client->mctx, + client->view->acceptexpired)) { + dst_key_free(&key); + dns_rdataset_disassociate(&keyrdataset); + mark_secure(client, db, name, rdataset, + sigrdataset); + return (ISC_TRUE); + } + dst_key_free(&key); + } while (1); + if (dns_rdataset_isassociated(&keyrdataset)) + dns_rdataset_disassociate(&keyrdataset); + } + return (ISC_FALSE); +} + +static void +query_addbestns(ns_client_t *client) { + dns_db_t *db, *zdb; + dns_dbnode_t *node; + dns_name_t *fname, *zfname; + dns_rdataset_t *rdataset, *sigrdataset, *zrdataset, *zsigrdataset; + isc_boolean_t is_zone, use_zone; + isc_buffer_t *dbuf; + isc_result_t result; + dns_dbversion_t *version; + dns_zone_t *zone; + isc_buffer_t b; + + CTRACE("query_addbestns"); + fname = NULL; + zfname = NULL; + rdataset = NULL; + zrdataset = NULL; + sigrdataset = NULL; + zsigrdataset = NULL; + node = NULL; + db = NULL; + zdb = NULL; + version = NULL; + zone = NULL; + is_zone = ISC_FALSE; + use_zone = ISC_FALSE; + + /* + * Find the right database. + */ + result = query_getdb(client, client->query.qname, dns_rdatatype_ns, 0, + &zone, &db, &version, &is_zone); + if (result != ISC_R_SUCCESS) + goto cleanup; + + db_find: + /* + * We'll need some resources... + */ + dbuf = query_getnamebuf(client); + if (dbuf == NULL) + goto cleanup; + fname = query_newname(client, dbuf, &b); + rdataset = query_newrdataset(client); + if (fname == NULL || rdataset == NULL) + goto cleanup; + /* + * Get the RRSIGs if the client requested them or if we may + * need to validate answers from the cache. + */ + if (WANTDNSSEC(client) || !is_zone) { + sigrdataset = query_newrdataset(client); + if (sigrdataset == NULL) + goto cleanup; + } + + /* + * Now look for the zonecut. + */ + if (is_zone) { + result = dns_db_find(db, client->query.qname, version, + dns_rdatatype_ns, client->query.dboptions, + client->now, &node, fname, + rdataset, sigrdataset); + if (result != DNS_R_DELEGATION) + goto cleanup; + if (USECACHE(client)) { + query_keepname(client, fname, dbuf); + zdb = db; + zfname = fname; + fname = NULL; + zrdataset = rdataset; + rdataset = NULL; + zsigrdataset = sigrdataset; + sigrdataset = NULL; + dns_db_detachnode(db, &node); + version = NULL; + db = NULL; + dns_db_attach(client->view->cachedb, &db); + is_zone = ISC_FALSE; + goto db_find; + } + } else { + result = dns_db_findzonecut(db, client->query.qname, + client->query.dboptions, + client->now, &node, fname, + rdataset, sigrdataset); + if (result == ISC_R_SUCCESS) { + if (zfname != NULL && + !dns_name_issubdomain(fname, zfname)) { + /* + * We found a zonecut in the cache, but our + * zone delegation is better. + */ + use_zone = ISC_TRUE; + } + } else if (result == ISC_R_NOTFOUND && zfname != NULL) { + /* + * We didn't find anything in the cache, but we + * have a zone delegation, so use it. + */ + use_zone = ISC_TRUE; + } else + goto cleanup; + } + + if (use_zone) { + query_releasename(client, &fname); + fname = zfname; + zfname = NULL; + /* + * We've already done query_keepname() on + * zfname, so we must set dbuf to NULL to + * prevent query_addrrset() from trying to + * call query_keepname() again. + */ + dbuf = NULL; + query_putrdataset(client, &rdataset); + if (sigrdataset != NULL) + query_putrdataset(client, &sigrdataset); + rdataset = zrdataset; + zrdataset = NULL; + sigrdataset = zsigrdataset; + zsigrdataset = NULL; + } + + /* + * Attempt to validate RRsets that are pending or that are glue. + */ + if ((rdataset->trust == dns_trust_pending || + (sigrdataset != NULL && sigrdataset->trust == dns_trust_pending)) + && !validate(client, db, fname, rdataset, sigrdataset) && + (client->query.dboptions & DNS_DBFIND_PENDINGOK) == 0) + goto cleanup; + + if ((rdataset->trust == dns_trust_glue || + (sigrdataset != NULL && sigrdataset->trust == dns_trust_glue)) && + !validate(client, db, fname, rdataset, sigrdataset) && + SECURE(client) && WANTDNSSEC(client)) + goto cleanup; + + /* + * If the client doesn't want DNSSEC we can discard the sigrdataset + * now. + */ + if (!WANTDNSSEC(client)) + query_putrdataset(client, &sigrdataset); + query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf, + DNS_SECTION_AUTHORITY); + + cleanup: + if (rdataset != NULL) + query_putrdataset(client, &rdataset); + if (sigrdataset != NULL) + query_putrdataset(client, &sigrdataset); + if (fname != NULL) + query_releasename(client, &fname); + if (node != NULL) + dns_db_detachnode(db, &node); + if (db != NULL) + dns_db_detach(&db); + if (zone != NULL) + dns_zone_detach(&zone); + if (zdb != NULL) { + query_putrdataset(client, &zrdataset); + if (zsigrdataset != NULL) + query_putrdataset(client, &zsigrdataset); + if (zfname != NULL) + query_releasename(client, &zfname); + dns_db_detach(&zdb); + } +} + +static void +query_addds(ns_client_t *client, dns_db_t *db, dns_dbnode_t *node, + dns_dbversion_t *version) +{ + dns_name_t *rname; + dns_rdataset_t *rdataset, *sigrdataset; + isc_result_t result; + + CTRACE("query_addds"); + rname = NULL; + rdataset = NULL; + sigrdataset = NULL; + + /* + * We'll need some resources... + */ + rdataset = query_newrdataset(client); + sigrdataset = query_newrdataset(client); + if (rdataset == NULL || sigrdataset == NULL) + goto cleanup; + + /* + * Look for the DS record, which may or may not be present. + */ + result = dns_db_findrdataset(db, node, version, dns_rdatatype_ds, 0, + client->now, rdataset, sigrdataset); + /* + * If we didn't find it, look for an NSEC. */ + if (result == ISC_R_NOTFOUND) + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_nsec, 0, client->now, + rdataset, sigrdataset); + if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) + goto cleanup; + if (!dns_rdataset_isassociated(rdataset) || + !dns_rdataset_isassociated(sigrdataset)) + goto cleanup; + + /* + * We've already added the NS record, so if the name's not there, + * we have other problems. Use this name rather than calling + * query_addrrset(). + */ + result = dns_message_firstname(client->message, DNS_SECTION_AUTHORITY); + if (result != ISC_R_SUCCESS) + goto cleanup; + + rname = NULL; + dns_message_currentname(client->message, DNS_SECTION_AUTHORITY, + &rname); + result = dns_message_findtype(rname, dns_rdatatype_ns, 0, NULL); + if (result != ISC_R_SUCCESS) + goto cleanup; + + ISC_LIST_APPEND(rname->list, rdataset, link); + ISC_LIST_APPEND(rname->list, sigrdataset, link); + rdataset = NULL; + sigrdataset = NULL; + + cleanup: + if (rdataset != NULL) + query_putrdataset(client, &rdataset); + if (sigrdataset != NULL) + query_putrdataset(client, &sigrdataset); +} + +static void +query_addwildcardproof(ns_client_t *client, dns_db_t *db, + dns_dbversion_t *version, dns_name_t *name, + isc_boolean_t ispositive) +{ + isc_buffer_t *dbuf, b; + dns_name_t *fname; + dns_rdataset_t *rdataset, *sigrdataset; + dns_fixedname_t wfixed; + dns_name_t *wname; + dns_dbnode_t *node; + unsigned int options; + unsigned int olabels, nlabels; + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_nsec_t nsec; + isc_boolean_t have_wname; + int order; + + CTRACE("query_addwildcardproof"); + fname = NULL; + rdataset = NULL; + sigrdataset = NULL; + node = NULL; + + /* + * Get the NOQNAME proof then if !ispositive + * get the NOWILDCARD proof. + * + * DNS_DBFIND_NOWILD finds the NSEC records that covers the + * name ignoring any wildcard. From the owner and next names + * of this record you can compute which wildcard (if it exists) + * will match by finding the longest common suffix of the + * owner name and next names with the qname and prefixing that + * with the wildcard label. + * + * e.g. + * Given: + * example SOA + * example NSEC b.example + * b.example A + * b.example NSEC a.d.example + * a.d.example A + * a.d.example NSEC g.f.example + * g.f.example A + * g.f.example NSEC z.i.example + * z.i.example A + * z.i.example NSEC example + * + * QNAME: + * a.example -> example NSEC b.example + * owner common example + * next common example + * wild *.example + * d.b.example -> b.example NSEC a.d.example + * owner common b.example + * next common example + * wild *.b.example + * a.f.example -> a.d.example NSEC g.f.example + * owner common example + * next common f.example + * wild *.f.example + * j.example -> z.i.example NSEC example + * owner common example + * next common example + * wild *.f.example + */ + options = client->query.dboptions | DNS_DBFIND_NOWILD; + dns_fixedname_init(&wfixed); + wname = dns_fixedname_name(&wfixed); + again: + have_wname = ISC_FALSE; + /* + * We'll need some resources... + */ + dbuf = query_getnamebuf(client); + if (dbuf == NULL) + goto cleanup; + fname = query_newname(client, dbuf, &b); + rdataset = query_newrdataset(client); + sigrdataset = query_newrdataset(client); + if (fname == NULL || rdataset == NULL || sigrdataset == NULL) + goto cleanup; + + result = dns_db_find(db, name, version, dns_rdatatype_nsec, options, + 0, &node, fname, rdataset, sigrdataset); + if (node != NULL) + dns_db_detachnode(db, &node); + if (result == DNS_R_NXDOMAIN) { + if (!ispositive) + result = dns_rdataset_first(rdataset); + if (result == ISC_R_SUCCESS) { + dns_rdataset_current(rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &nsec, NULL); + } + if (result == ISC_R_SUCCESS) { + (void)dns_name_fullcompare(name, fname, &order, + &olabels); + (void)dns_name_fullcompare(name, &nsec.next, &order, + &nlabels); + /* + * Check for a pathological condition created when + * serving some malformed signed zones and bail out. + */ + if (dns_name_countlabels(name) == nlabels) + goto cleanup; + + if (olabels > nlabels) + dns_name_split(name, olabels, NULL, wname); + else + dns_name_split(name, nlabels, NULL, wname); + result = dns_name_concatenate(dns_wildcardname, + wname, wname, NULL); + if (result == ISC_R_SUCCESS) + have_wname = ISC_TRUE; + dns_rdata_freestruct(&nsec); + } + query_addrrset(client, &fname, &rdataset, &sigrdataset, + dbuf, DNS_SECTION_AUTHORITY); + } + if (rdataset != NULL) + query_putrdataset(client, &rdataset); + if (sigrdataset != NULL) + query_putrdataset(client, &sigrdataset); + if (fname != NULL) + query_releasename(client, &fname); + if (have_wname) { + ispositive = ISC_TRUE; /* prevent loop */ + if (!dns_name_equal(name, wname)) { + name = wname; + goto again; + } + } + cleanup: + if (rdataset != NULL) + query_putrdataset(client, &rdataset); + if (sigrdataset != NULL) + query_putrdataset(client, &sigrdataset); + if (fname != NULL) + query_releasename(client, &fname); +} + +static void +query_addnxrrsetnsec(ns_client_t *client, dns_db_t *db, + dns_dbversion_t *version, dns_name_t **namep, + dns_rdataset_t **rdatasetp, dns_rdataset_t **sigrdatasetp) +{ + dns_name_t *name; + dns_rdataset_t *sigrdataset; + dns_rdata_t sigrdata; + dns_rdata_rrsig_t sig; + unsigned int labels; + isc_buffer_t *dbuf, b; + dns_name_t *fname; + isc_result_t result; + + name = *namep; + if ((name->attributes & DNS_NAMEATTR_WILDCARD) == 0) { + query_addrrset(client, namep, rdatasetp, sigrdatasetp, + NULL, DNS_SECTION_AUTHORITY); + return; + } + + if (sigrdatasetp == NULL) + return; + sigrdataset = *sigrdatasetp; + if (sigrdataset == NULL || !dns_rdataset_isassociated(sigrdataset)) + return; + result = dns_rdataset_first(sigrdataset); + if (result != ISC_R_SUCCESS) + return; + dns_rdata_init(&sigrdata); + dns_rdataset_current(sigrdataset, &sigrdata); + result = dns_rdata_tostruct(&sigrdata, &sig, NULL); + if (result != ISC_R_SUCCESS) + return; + + labels = dns_name_countlabels(name); + if ((unsigned int)sig.labels + 1 >= labels) + return; + + /* XXX */ + query_addwildcardproof(client, db, version, client->query.qname, + ISC_TRUE); + + /* + * We'll need some resources... + */ + dbuf = query_getnamebuf(client); + if (dbuf == NULL) + return; + fname = query_newname(client, dbuf, &b); + if (fname == NULL) + return; + dns_name_split(name, sig.labels + 1, NULL, fname); + /* This will succeed, since we've stripped labels. */ + RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname, fname, fname, + NULL) == ISC_R_SUCCESS); + query_addrrset(client, &fname, rdatasetp, sigrdatasetp, + dbuf, DNS_SECTION_AUTHORITY); +} + +static void +query_resume(isc_task_t *task, isc_event_t *event) { + dns_fetchevent_t *devent = (dns_fetchevent_t *)event; + dns_fetch_t *fetch; + ns_client_t *client; + isc_boolean_t fetch_canceled, client_shuttingdown; + isc_result_t result; + isc_logcategory_t *logcategory = NS_LOGCATEGORY_QUERY_EERRORS; + int errorloglevel; + + /* + * Resume a query after recursion. + */ + + UNUSED(task); + + REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE); + client = devent->ev_arg; + REQUIRE(NS_CLIENT_VALID(client)); + REQUIRE(task == client->task); + REQUIRE(RECURSING(client)); + + LOCK(&client->query.fetchlock); + if (client->query.fetch != NULL) { + /* + * This is the fetch we've been waiting for. + */ + INSIST(devent->fetch == client->query.fetch); + client->query.fetch = NULL; + fetch_canceled = ISC_FALSE; + /* + * Update client->now. + */ + isc_stdtime_get(&client->now); + } else { + /* + * This is a fetch completion event for a canceled fetch. + * Clean up and don't resume the find. + */ + fetch_canceled = ISC_TRUE; + } + UNLOCK(&client->query.fetchlock); + INSIST(client->query.fetch == NULL); + + client->query.attributes &= ~NS_QUERYATTR_RECURSING; + fetch = devent->fetch; + devent->fetch = NULL; + + /* + * If this client is shutting down, or this transaction + * has timed out, do not resume the find. + */ + client_shuttingdown = ns_client_shuttingdown(client); + if (fetch_canceled || client_shuttingdown) { + if (devent->node != NULL) + dns_db_detachnode(devent->db, &devent->node); + if (devent->db != NULL) + dns_db_detach(&devent->db); + query_putrdataset(client, &devent->rdataset); + if (devent->sigrdataset != NULL) + query_putrdataset(client, &devent->sigrdataset); + isc_event_free(&event); + if (fetch_canceled) + query_error(client, DNS_R_SERVFAIL, __LINE__); + else + query_next(client, ISC_R_CANCELED); + /* + * This may destroy the client. + */ + ns_client_detach(&client); + } else { + result = query_find(client, devent, 0); + if (result != ISC_R_SUCCESS) { + if (result == DNS_R_SERVFAIL) + errorloglevel = ISC_LOG_DEBUG(2); + else + errorloglevel = ISC_LOG_DEBUG(4); + if (isc_log_wouldlog(ns_g_lctx, errorloglevel)) { + dns_resolver_logfetch(fetch, ns_g_lctx, + logcategory, + NS_LOGMODULE_QUERY, + errorloglevel, ISC_FALSE); + } + } + } + + dns_resolver_destroyfetch(&fetch); +} + +static isc_result_t +query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qdomain, + dns_rdataset_t *nameservers, isc_boolean_t resuming) +{ + isc_result_t result; + dns_rdataset_t *rdataset, *sigrdataset; + isc_sockaddr_t *peeraddr; + + if (!resuming) + inc_stats(client, dns_nsstatscounter_recursion); + + /* + * We are about to recurse, which means that this client will + * be unavailable for serving new requests for an indeterminate + * amount of time. If this client is currently responsible + * for handling incoming queries, set up a new client + * object to handle them while we are waiting for a + * response. There is no need to replace TCP clients + * because those have already been replaced when the + * connection was accepted (if allowed by the TCP quota). + */ + if (client->recursionquota == NULL) { + result = isc_quota_attach(&ns_g_server->recursionquota, + &client->recursionquota); + if (result == ISC_R_SOFTQUOTA) { + static isc_stdtime_t last = 0; + isc_stdtime_t now; + isc_stdtime_get(&now); + if (now != last) { + last = now; + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_QUERY, + ISC_LOG_WARNING, + "recursive-clients soft limit " + "exceeded, aborting oldest query"); + } + ns_client_killoldestquery(client); + result = ISC_R_SUCCESS; + } else if (result == ISC_R_QUOTA) { + static isc_stdtime_t last = 0; + isc_stdtime_t now; + isc_stdtime_get(&now); + if (now != last) { + last = now; + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_QUERY, + ISC_LOG_WARNING, + "no more recursive clients: %s", + isc_result_totext(result)); + } + ns_client_killoldestquery(client); + } + if (result == ISC_R_SUCCESS && !client->mortal && + (client->attributes & NS_CLIENTATTR_TCP) == 0) { + result = ns_client_replace(client); + if (result != ISC_R_SUCCESS) { + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_QUERY, + ISC_LOG_WARNING, + "ns_client_replace() failed: %s", + isc_result_totext(result)); + isc_quota_detach(&client->recursionquota); + } + } + if (result != ISC_R_SUCCESS) + return (result); + ns_client_recursing(client); + } + + /* + * Invoke the resolver. + */ + REQUIRE(nameservers == NULL || nameservers->type == dns_rdatatype_ns); + REQUIRE(client->query.fetch == NULL); + + rdataset = query_newrdataset(client); + if (rdataset == NULL) + return (ISC_R_NOMEMORY); + if (WANTDNSSEC(client)) { + sigrdataset = query_newrdataset(client); + if (sigrdataset == NULL) { + query_putrdataset(client, &rdataset); + return (ISC_R_NOMEMORY); + } + } else + sigrdataset = NULL; + + if (client->query.timerset == ISC_FALSE) + ns_client_settimeout(client, 60); + if ((client->attributes & NS_CLIENTATTR_TCP) == 0) + peeraddr = &client->peeraddr; + else + peeraddr = NULL; + result = dns_resolver_createfetch2(client->view->resolver, + client->query.qname, + qtype, qdomain, nameservers, + NULL, peeraddr, client->message->id, + client->query.fetchoptions, + client->task, + query_resume, client, + rdataset, sigrdataset, + &client->query.fetch); + + if (result == ISC_R_SUCCESS) { + /* + * Record that we're waiting for an event. A client which + * is shutting down will not be destroyed until all the + * events have been received. + */ + } else { + query_putrdataset(client, &rdataset); + if (sigrdataset != NULL) + query_putrdataset(client, &sigrdataset); + } + + return (result); +} + +#define MAX_RESTARTS 16 + +#define QUERY_ERROR(r) \ +do { \ + eresult = r; \ + want_restart = ISC_FALSE; \ + line = __LINE__; \ +} while (0) + +/* + * Extract a network address from the RDATA of an A or AAAA + * record. + * + * Returns: + * ISC_R_SUCCESS + * ISC_R_NOTIMPLEMENTED The rdata is not a known address type. + */ +static isc_result_t +rdata_tonetaddr(const dns_rdata_t *rdata, isc_netaddr_t *netaddr) { + struct in_addr ina; + struct in6_addr in6a; + + switch (rdata->type) { + case dns_rdatatype_a: + INSIST(rdata->length == 4); + memcpy(&ina.s_addr, rdata->data, 4); + isc_netaddr_fromin(netaddr, &ina); + return (ISC_R_SUCCESS); + case dns_rdatatype_aaaa: + INSIST(rdata->length == 16); + memcpy(in6a.s6_addr, rdata->data, 16); + isc_netaddr_fromin6(netaddr, &in6a); + return (ISC_R_SUCCESS); + default: + return (ISC_R_NOTIMPLEMENTED); + } +} + +/* + * Find the sort order of 'rdata' in the topology-like + * ACL forming the second element in a 2-element top-level + * sortlist statement. + */ +static int +query_sortlist_order_2element(const dns_rdata_t *rdata, const void *arg) { + isc_netaddr_t netaddr; + + if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS) + return (INT_MAX); + return (ns_sortlist_addrorder2(&netaddr, arg)); +} + +/* + * Find the sort order of 'rdata' in the matching element + * of a 1-element top-level sortlist statement. + */ +static int +query_sortlist_order_1element(const dns_rdata_t *rdata, const void *arg) { + isc_netaddr_t netaddr; + + if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS) + return (INT_MAX); + return (ns_sortlist_addrorder1(&netaddr, arg)); +} + +/* + * Find the sortlist statement that applies to 'client' and set up + * the sortlist info in in client->message appropriately. + */ +static void +setup_query_sortlist(ns_client_t *client) { + isc_netaddr_t netaddr; + dns_rdatasetorderfunc_t order = NULL; + const void *order_arg = NULL; + + isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); + switch (ns_sortlist_setup(client->view->sortlist, + &netaddr, &order_arg)) { + case NS_SORTLISTTYPE_1ELEMENT: + order = query_sortlist_order_1element; + break; + case NS_SORTLISTTYPE_2ELEMENT: + order = query_sortlist_order_2element; + break; + case NS_SORTLISTTYPE_NONE: + order = NULL; + break; + default: + INSIST(0); + break; + } + dns_message_setsortorder(client->message, order, order_arg); +} + +static void +query_addnoqnameproof(ns_client_t *client, dns_rdataset_t *rdataset) { + isc_buffer_t *dbuf, b; + dns_name_t *fname; + dns_rdataset_t *nsec, *nsecsig; + isc_result_t result = ISC_R_NOMEMORY; + + CTRACE("query_addnoqnameproof"); + + fname = NULL; + nsec = NULL; + nsecsig = NULL; + + dbuf = query_getnamebuf(client); + if (dbuf == NULL) + goto cleanup; + fname = query_newname(client, dbuf, &b); + nsec = query_newrdataset(client); + nsecsig = query_newrdataset(client); + if (fname == NULL || nsec == NULL || nsecsig == NULL) + goto cleanup; + + result = dns_rdataset_getnoqname(rdataset, fname, nsec, nsecsig); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + query_addrrset(client, &fname, &nsec, &nsecsig, dbuf, + DNS_SECTION_AUTHORITY); + + cleanup: + if (nsec != NULL) + query_putrdataset(client, &nsec); + if (nsecsig != NULL) + query_putrdataset(client, &nsecsig); + if (fname != NULL) + query_releasename(client, &fname); +} + +static inline void +answer_in_glue(ns_client_t *client, dns_rdatatype_t qtype) { + dns_name_t *name; + dns_message_t *msg; + dns_section_t section = DNS_SECTION_ADDITIONAL; + dns_rdataset_t *rdataset = NULL; + + msg = client->message; + for (name = ISC_LIST_HEAD(msg->sections[section]); + name != NULL; + name = ISC_LIST_NEXT(name, link)) + if (dns_name_equal(name, client->query.qname)) { + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) + if (rdataset->type == qtype) + break; + break; + } + if (rdataset != NULL) { + ISC_LIST_UNLINK(msg->sections[section], name, link); + ISC_LIST_PREPEND(msg->sections[section], name, link); + ISC_LIST_UNLINK(name->list, rdataset, link); + ISC_LIST_PREPEND(name->list, rdataset, link); + rdataset->attributes |= DNS_RDATASETATTR_REQUIREDGLUE; + } +} + +#define NS_NAME_INIT(A,B) \ + { \ + DNS_NAME_MAGIC, \ + A, sizeof(A), sizeof(B), \ + DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, \ + B, NULL, { (void *)-1, (void *)-1}, \ + {NULL, NULL} \ + } + +static unsigned char inaddr10_offsets[] = { 0, 3, 11, 16 }; +static unsigned char inaddr172_offsets[] = { 0, 3, 7, 15, 20 }; +static unsigned char inaddr192_offsets[] = { 0, 4, 8, 16, 21 }; + +static unsigned char inaddr10[] = "\00210\007IN-ADDR\004ARPA"; + +static unsigned char inaddr16172[] = "\00216\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr17172[] = "\00217\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr18172[] = "\00218\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr19172[] = "\00219\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr20172[] = "\00220\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr21172[] = "\00221\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr22172[] = "\00222\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr23172[] = "\00223\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr24172[] = "\00224\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr25172[] = "\00225\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr26172[] = "\00226\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr27172[] = "\00227\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr28172[] = "\00228\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr29172[] = "\00229\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr30172[] = "\00230\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr31172[] = "\00231\003172\007IN-ADDR\004ARPA"; + +static unsigned char inaddr168192[] = "\003168\003192\007IN-ADDR\004ARPA"; + +static dns_name_t rfc1918names[] = { + NS_NAME_INIT(inaddr10, inaddr10_offsets), + NS_NAME_INIT(inaddr16172, inaddr172_offsets), + NS_NAME_INIT(inaddr17172, inaddr172_offsets), + NS_NAME_INIT(inaddr18172, inaddr172_offsets), + NS_NAME_INIT(inaddr19172, inaddr172_offsets), + NS_NAME_INIT(inaddr20172, inaddr172_offsets), + NS_NAME_INIT(inaddr21172, inaddr172_offsets), + NS_NAME_INIT(inaddr22172, inaddr172_offsets), + NS_NAME_INIT(inaddr23172, inaddr172_offsets), + NS_NAME_INIT(inaddr24172, inaddr172_offsets), + NS_NAME_INIT(inaddr25172, inaddr172_offsets), + NS_NAME_INIT(inaddr26172, inaddr172_offsets), + NS_NAME_INIT(inaddr27172, inaddr172_offsets), + NS_NAME_INIT(inaddr28172, inaddr172_offsets), + NS_NAME_INIT(inaddr29172, inaddr172_offsets), + NS_NAME_INIT(inaddr30172, inaddr172_offsets), + NS_NAME_INIT(inaddr31172, inaddr172_offsets), + NS_NAME_INIT(inaddr168192, inaddr192_offsets) +}; + + +static unsigned char prisoner_data[] = "\010prisoner\004iana\003org"; +static unsigned char hostmaster_data[] = "\012hostmaster\014root-servers\003org"; + +static unsigned char prisoner_offsets[] = { 0, 9, 14, 18 }; +static unsigned char hostmaster_offsets[] = { 0, 11, 24, 28 }; + +static dns_name_t prisoner = NS_NAME_INIT(prisoner_data, prisoner_offsets); +static dns_name_t hostmaster = NS_NAME_INIT(hostmaster_data, hostmaster_offsets); + +static void +warn_rfc1918(ns_client_t *client, dns_name_t *fname, dns_rdataset_t *rdataset) { + unsigned int i; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_soa_t soa; + dns_rdataset_t found; + isc_result_t result; + + for (i = 0; i < (sizeof(rfc1918names)/sizeof(*rfc1918names)); i++) { + if (dns_name_issubdomain(fname, &rfc1918names[i])) { + dns_rdataset_init(&found); + result = dns_ncache_getrdataset(rdataset, + &rfc1918names[i], + dns_rdatatype_soa, + &found); + if (result != ISC_R_SUCCESS) + return; + + result = dns_rdataset_first(&found); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + dns_rdataset_current(&found, &rdata); + result = dns_rdata_tostruct(&rdata, &soa, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + if (dns_name_equal(&soa.origin, &prisoner) && + dns_name_equal(&soa.contact, &hostmaster)) { + char buf[DNS_NAME_FORMATSIZE]; + dns_name_format(fname, buf, sizeof(buf)); + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_QUERY, + ISC_LOG_WARNING, + "RFC 1918 response from " + "Internet for %s", buf); + } + dns_rdataset_disassociate(&found); + return; + } + } +} + +/* + * Do the bulk of query processing for the current query of 'client'. + * If 'event' is non-NULL, we are returning from recursion and 'qtype' + * is ignored. Otherwise, 'qtype' is the query type. + */ +static isc_result_t +query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) +{ + dns_db_t *db, *zdb; + dns_dbnode_t *node; + dns_rdatatype_t type; + dns_name_t *fname, *zfname, *tname, *prefix; + dns_rdataset_t *rdataset, *trdataset; + dns_rdataset_t *sigrdataset, *zrdataset, *zsigrdataset; + dns_rdataset_t **sigrdatasetp; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdatasetiter_t *rdsiter; + isc_boolean_t want_restart, authoritative, is_zone, need_wildcardproof; + unsigned int n, nlabels; + dns_namereln_t namereln; + int order; + isc_buffer_t *dbuf; + isc_buffer_t b; + isc_result_t result, eresult; + dns_fixedname_t fixed; + dns_fixedname_t wildcardname; + dns_dbversion_t *version; + dns_zone_t *zone; + dns_rdata_cname_t cname; + dns_rdata_dname_t dname; + unsigned int options; + isc_boolean_t empty_wild; + dns_rdataset_t *noqname; + isc_boolean_t resuming; + int line = -1; + + CTRACE("query_find"); + + /* + * One-time initialization. + * + * It's especially important to initialize anything that the cleanup + * code might cleanup. + */ + + eresult = ISC_R_SUCCESS; + fname = NULL; + zfname = NULL; + rdataset = NULL; + zrdataset = NULL; + sigrdataset = NULL; + zsigrdataset = NULL; + node = NULL; + db = NULL; + zdb = NULL; + version = NULL; + zone = NULL; + need_wildcardproof = ISC_FALSE; + empty_wild = ISC_FALSE; + options = 0; + resuming = ISC_FALSE; + is_zone = ISC_FALSE; + + if (event != NULL) { + /* + * We're returning from recursion. Restore the query context + * and resume. + */ + + want_restart = ISC_FALSE; + authoritative = ISC_FALSE; + + qtype = event->qtype; + if (qtype == dns_rdatatype_rrsig || qtype == dns_rdatatype_sig) + type = dns_rdatatype_any; + else + type = qtype; + db = event->db; + node = event->node; + rdataset = event->rdataset; + sigrdataset = event->sigrdataset; + + /* + * We'll need some resources... + */ + dbuf = query_getnamebuf(client); + if (dbuf == NULL) { + QUERY_ERROR(DNS_R_SERVFAIL); + goto cleanup; + } + fname = query_newname(client, dbuf, &b); + if (fname == NULL) { + QUERY_ERROR(DNS_R_SERVFAIL); + goto cleanup; + } + tname = dns_fixedname_name(&event->foundname); + result = dns_name_copy(tname, fname, NULL); + if (result != ISC_R_SUCCESS) { + QUERY_ERROR(DNS_R_SERVFAIL); + goto cleanup; + } + + result = event->result; + resuming = ISC_TRUE; + + goto resume; + } + + /* + * Not returning from recursion. + */ + + /* + * If it's a SIG query, we'll iterate the node. + */ + if (qtype == dns_rdatatype_rrsig || qtype == dns_rdatatype_sig) + type = dns_rdatatype_any; + else + type = qtype; + + restart: + CTRACE("query_find: restart"); + want_restart = ISC_FALSE; + authoritative = ISC_FALSE; + version = NULL; + need_wildcardproof = ISC_FALSE; + + if (client->view->checknames && + !dns_rdata_checkowner(client->query.qname, + client->message->rdclass, + qtype, ISC_FALSE)) { + char namebuf[DNS_NAME_FORMATSIZE]; + char typename[DNS_RDATATYPE_FORMATSIZE]; + char classname[DNS_RDATACLASS_FORMATSIZE]; + + dns_name_format(client->query.qname, namebuf, sizeof(namebuf)); + dns_rdatatype_format(qtype, typename, sizeof(typename)); + dns_rdataclass_format(client->message->rdclass, classname, + sizeof(classname)); + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_QUERY, ISC_LOG_ERROR, + "check-names failure %s/%s/%s", namebuf, + typename, classname); + QUERY_ERROR(DNS_R_REFUSED); + goto cleanup; + } + + /* + * First we must find the right database. + */ + options &= DNS_GETDB_NOLOG; /* Preserve DNS_GETDB_NOLOG. */ + if (dns_rdatatype_atparent(qtype) && + !dns_name_equal(client->query.qname, dns_rootname)) + options |= DNS_GETDB_NOEXACT; + result = query_getdb(client, client->query.qname, qtype, options, + &zone, &db, &version, &is_zone); + if ((result != ISC_R_SUCCESS || !is_zone) && !RECURSIONOK(client) && + (options & DNS_GETDB_NOEXACT) != 0 && qtype == dns_rdatatype_ds) { + /* + * Look to see if we are authoritative for the + * child zone if the query type is DS. + */ + dns_db_t *tdb = NULL; + dns_zone_t *tzone = NULL; + dns_dbversion_t *tversion = NULL; + isc_result_t tresult; + + tresult = query_getzonedb(client, client->query.qname, qtype, + DNS_GETDB_PARTIAL, &tzone, &tdb, + &tversion); + if (tresult == ISC_R_SUCCESS) { + options &= ~DNS_GETDB_NOEXACT; + query_putrdataset(client, &rdataset); + if (db != NULL) + dns_db_detach(&db); + if (zone != NULL) + dns_zone_detach(&zone); + version = tversion; + db = tdb; + zone = tzone; + is_zone = ISC_TRUE; + result = ISC_R_SUCCESS; + } else { + if (tdb != NULL) + dns_db_detach(&tdb); + if (tzone != NULL) + dns_zone_detach(&tzone); + } + } + if (result != ISC_R_SUCCESS) { + if (result == DNS_R_REFUSED) { + if (WANTRECURSION(client)) { + inc_stats(client, + dns_nsstatscounter_recurserej); + } else + inc_stats(client, dns_nsstatscounter_authrej); + if (!PARTIALANSWER(client)) + QUERY_ERROR(DNS_R_REFUSED); + } else + QUERY_ERROR(DNS_R_SERVFAIL); + goto cleanup; + } + + if (is_zone) + authoritative = ISC_TRUE; + + if (event == NULL && client->query.restarts == 0) { + if (is_zone) { +#ifdef DLZ + if (zone != NULL) { + /* + * if is_zone = true, zone = NULL then this is + * a DLZ zone. Don't attempt to attach zone. + */ +#endif + dns_zone_attach(zone, &client->query.authzone); +#ifdef DLZ + } +#endif + dns_db_attach(db, &client->query.authdb); + } + client->query.authdbset = ISC_TRUE; + } + + db_find: + CTRACE("query_find: db_find"); + /* + * We'll need some resources... + */ + dbuf = query_getnamebuf(client); + if (dbuf == NULL) { + QUERY_ERROR(DNS_R_SERVFAIL); + goto cleanup; + } + fname = query_newname(client, dbuf, &b); + rdataset = query_newrdataset(client); + if (fname == NULL || rdataset == NULL) { + QUERY_ERROR(DNS_R_SERVFAIL); + goto cleanup; + } + if (WANTDNSSEC(client)) { + sigrdataset = query_newrdataset(client); + if (sigrdataset == NULL) { + QUERY_ERROR(DNS_R_SERVFAIL); + goto cleanup; + } + } + + /* + * Now look for an answer in the database. + */ + result = dns_db_find(db, client->query.qname, version, type, + client->query.dboptions, client->now, + &node, fname, rdataset, sigrdataset); + + resume: + CTRACE("query_find: resume"); + switch (result) { + case ISC_R_SUCCESS: + /* + * This case is handled in the main line below. + */ + break; + case DNS_R_GLUE: + case DNS_R_ZONECUT: + /* + * These cases are handled in the main line below. + */ + INSIST(is_zone); + authoritative = ISC_FALSE; + break; + case ISC_R_NOTFOUND: + /* + * The cache doesn't even have the root NS. Get them from + * the hints DB. + */ + INSIST(!is_zone); + if (db != NULL) + dns_db_detach(&db); + + if (client->view->hints == NULL) { + /* We have no hints. */ + result = ISC_R_FAILURE; + } else { + dns_db_attach(client->view->hints, &db); + result = dns_db_find(db, dns_rootname, + NULL, dns_rdatatype_ns, + 0, client->now, &node, fname, + rdataset, sigrdataset); + } + if (result != ISC_R_SUCCESS) { + /* + * Nonsensical root hints may require cleanup. + */ + if (dns_rdataset_isassociated(rdataset)) + dns_rdataset_disassociate(rdataset); + if (sigrdataset != NULL && + dns_rdataset_isassociated(sigrdataset)) + dns_rdataset_disassociate(sigrdataset); + if (node != NULL) + dns_db_detachnode(db, &node); + + /* + * We don't have any root server hints, but + * we may have working forwarders, so try to + * recurse anyway. + */ + if (RECURSIONOK(client)) { + result = query_recurse(client, qtype, + NULL, NULL, resuming); + if (result == ISC_R_SUCCESS) + client->query.attributes |= + NS_QUERYATTR_RECURSING; + else if (result == DNS_R_DUPLICATE || + result == DNS_R_DROP) { + /* Duplicate query. */ + QUERY_ERROR(result); + } else { + /* Unable to recurse. */ + QUERY_ERROR(DNS_R_SERVFAIL); + } + goto cleanup; + } else { + /* Unable to give root server referral. */ + QUERY_ERROR(DNS_R_SERVFAIL); + goto cleanup; + } + } + /* + * XXXRTH We should trigger root server priming here. + */ + /* FALLTHROUGH */ + case DNS_R_DELEGATION: + authoritative = ISC_FALSE; + if (is_zone) { + /* + * Look to see if we are authoritative for the + * child zone if the query type is DS. + */ + if (!RECURSIONOK(client) && + (options & DNS_GETDB_NOEXACT) != 0 && + qtype == dns_rdatatype_ds) { + dns_db_t *tdb = NULL; + dns_zone_t *tzone = NULL; + dns_dbversion_t *tversion = NULL; + result = query_getzonedb(client, + client->query.qname, + qtype, + DNS_GETDB_PARTIAL, + &tzone, &tdb, + &tversion); + if (result == ISC_R_SUCCESS) { + options &= ~DNS_GETDB_NOEXACT; + query_putrdataset(client, &rdataset); + if (sigrdataset != NULL) + query_putrdataset(client, + &sigrdataset); + if (fname != NULL) + query_releasename(client, + &fname); + if (node != NULL) + dns_db_detachnode(db, &node); + if (db != NULL) + dns_db_detach(&db); + if (zone != NULL) + dns_zone_detach(&zone); + version = tversion; + db = tdb; + zone = tzone; + authoritative = ISC_TRUE; + goto db_find; + } + if (tdb != NULL) + dns_db_detach(&tdb); + if (tzone != NULL) + dns_zone_detach(&tzone); + } + /* + * We're authoritative for an ancestor of QNAME. + */ + if (!USECACHE(client) || !RECURSIONOK(client)) { + /* + * If we don't have a cache, this is the best + * answer. + * + * If the client is making a nonrecursive + * query we always give out the authoritative + * delegation. This way even if we get + * junk in our cache, we won't fail in our + * role as the delegating authority if another + * nameserver asks us about a delegated + * subzone. + * + * We enable the retrieval of glue for this + * database by setting client->query.gluedb. + */ + client->query.gluedb = db; + client->query.isreferral = ISC_TRUE; + /* + * We must ensure NOADDITIONAL is off, + * because the generation of + * additional data is required in + * delegations. + */ + client->query.attributes &= + ~NS_QUERYATTR_NOADDITIONAL; + if (sigrdataset != NULL) + sigrdatasetp = &sigrdataset; + else + sigrdatasetp = NULL; + query_addrrset(client, &fname, + &rdataset, sigrdatasetp, + dbuf, DNS_SECTION_AUTHORITY); + client->query.gluedb = NULL; + if (WANTDNSSEC(client) && dns_db_issecure(db)) + query_addds(client, db, node, version); + } else { + /* + * We might have a better answer or delegation + * in the cache. We'll remember the current + * values of fname, rdataset, and sigrdataset. + * We'll then go looking for QNAME in the + * cache. If we find something better, we'll + * use it instead. + */ + query_keepname(client, fname, dbuf); + zdb = db; + zfname = fname; + fname = NULL; + zrdataset = rdataset; + rdataset = NULL; + zsigrdataset = sigrdataset; + sigrdataset = NULL; + dns_db_detachnode(db, &node); + version = NULL; + db = NULL; + dns_db_attach(client->view->cachedb, &db); + is_zone = ISC_FALSE; + goto db_find; + } + } else { + if (zfname != NULL && + !dns_name_issubdomain(fname, zfname)) { + /* + * We've already got a delegation from + * authoritative data, and it is better + * than what we found in the cache. Use + * it instead of the cache delegation. + */ + query_releasename(client, &fname); + fname = zfname; + zfname = NULL; + /* + * We've already done query_keepname() on + * zfname, so we must set dbuf to NULL to + * prevent query_addrrset() from trying to + * call query_keepname() again. + */ + dbuf = NULL; + query_putrdataset(client, &rdataset); + if (sigrdataset != NULL) + query_putrdataset(client, + &sigrdataset); + rdataset = zrdataset; + zrdataset = NULL; + sigrdataset = zsigrdataset; + zsigrdataset = NULL; + /* + * We don't clean up zdb here because we + * may still need it. It will get cleaned + * up by the main cleanup code. + */ + } + + if (RECURSIONOK(client)) { + /* + * Recurse! + */ + if (dns_rdatatype_atparent(type)) + result = query_recurse(client, qtype, + NULL, NULL, + resuming); + else + result = query_recurse(client, qtype, + fname, rdataset, + resuming); + if (result == ISC_R_SUCCESS) + client->query.attributes |= + NS_QUERYATTR_RECURSING; + else if (result == DNS_R_DUPLICATE || + result == DNS_R_DROP) + QUERY_ERROR(result); + else + QUERY_ERROR(DNS_R_SERVFAIL); + } else { + /* + * This is the best answer. + */ + client->query.attributes |= + NS_QUERYATTR_CACHEGLUEOK; + client->query.gluedb = zdb; + client->query.isreferral = ISC_TRUE; + /* + * We must ensure NOADDITIONAL is off, + * because the generation of + * additional data is required in + * delegations. + */ + client->query.attributes &= + ~NS_QUERYATTR_NOADDITIONAL; + if (sigrdataset != NULL) + sigrdatasetp = &sigrdataset; + else + sigrdatasetp = NULL; + query_addrrset(client, &fname, + &rdataset, sigrdatasetp, + dbuf, DNS_SECTION_AUTHORITY); + client->query.gluedb = NULL; + client->query.attributes &= + ~NS_QUERYATTR_CACHEGLUEOK; + if (WANTDNSSEC(client)) + query_addds(client, db, node, version); + } + } + goto cleanup; + case DNS_R_EMPTYNAME: + result = DNS_R_NXRRSET; + /* FALLTHROUGH */ + case DNS_R_NXRRSET: + INSIST(is_zone); + if (dns_rdataset_isassociated(rdataset)) { + /* + * If we've got a NSEC record, we need to save the + * name now because we're going call query_addsoa() + * below, and it needs to use the name buffer. + */ + query_keepname(client, fname, dbuf); + } else { + /* + * We're not going to use fname, and need to release + * our hold on the name buffer so query_addsoa() + * may use it. + */ + query_releasename(client, &fname); + } + /* + * Add SOA. + */ + result = query_addsoa(client, db, version, ISC_FALSE); + if (result != ISC_R_SUCCESS) { + QUERY_ERROR(result); + goto cleanup; + } + /* + * Add NSEC record if we found one. + */ + if (WANTDNSSEC(client)) { + if (dns_rdataset_isassociated(rdataset)) + query_addnxrrsetnsec(client, db, version, + &fname, &rdataset, + &sigrdataset); + } + goto cleanup; + case DNS_R_EMPTYWILD: + empty_wild = ISC_TRUE; + /* FALLTHROUGH */ + case DNS_R_NXDOMAIN: + INSIST(is_zone); + if (dns_rdataset_isassociated(rdataset)) { + /* + * If we've got a NSEC record, we need to save the + * name now because we're going call query_addsoa() + * below, and it needs to use the name buffer. + */ + query_keepname(client, fname, dbuf); + } else { + /* + * We're not going to use fname, and need to release + * our hold on the name buffer so query_addsoa() + * may use it. + */ + query_releasename(client, &fname); + } + /* + * Add SOA. If the query was for a SOA record force the + * ttl to zero so that it is possible for clients to find + * the containing zone of an arbitrary name with a stub + * resolver and not have it cached. + */ + if (qtype == dns_rdatatype_soa && +#ifdef DLZ + zone != NULL && +#endif + dns_zone_getzeronosoattl(zone)) + result = query_addsoa(client, db, version, ISC_TRUE); + else + result = query_addsoa(client, db, version, ISC_FALSE); + if (result != ISC_R_SUCCESS) { + QUERY_ERROR(result); + goto cleanup; + } + /* + * Add NSEC record if we found one. + */ + if (dns_rdataset_isassociated(rdataset)) { + if (WANTDNSSEC(client)) { + query_addrrset(client, &fname, &rdataset, + &sigrdataset, + NULL, DNS_SECTION_AUTHORITY); + query_addwildcardproof(client, db, version, + client->query.qname, + ISC_FALSE); + } + } + /* + * Set message rcode. + */ + if (empty_wild) + client->message->rcode = dns_rcode_noerror; + else + client->message->rcode = dns_rcode_nxdomain; + goto cleanup; + case DNS_R_NCACHENXDOMAIN: + case DNS_R_NCACHENXRRSET: + INSIST(!is_zone); + authoritative = ISC_FALSE; + /* + * Set message rcode, if required. + */ + if (result == DNS_R_NCACHENXDOMAIN) + client->message->rcode = dns_rcode_nxdomain; + /* + * Look for RFC 1918 leakage from Internet. + */ + if (result == DNS_R_NCACHENXDOMAIN && + qtype == dns_rdatatype_ptr && + client->message->rdclass == dns_rdataclass_in && + dns_name_countlabels(fname) == 7) + warn_rfc1918(client, fname, rdataset); + /* + * We don't call query_addrrset() because we don't need any + * of its extra features (and things would probably break!). + */ + query_keepname(client, fname, dbuf); + dns_message_addname(client->message, fname, + DNS_SECTION_AUTHORITY); + ISC_LIST_APPEND(fname->list, rdataset, link); + fname = NULL; + rdataset = NULL; + goto cleanup; + case DNS_R_CNAME: + /* + * Keep a copy of the rdataset. We have to do this because + * query_addrrset may clear 'rdataset' (to prevent the + * cleanup code from cleaning it up). + */ + trdataset = rdataset; + /* + * Add the CNAME to the answer section. + */ + if (sigrdataset != NULL) + sigrdatasetp = &sigrdataset; + else + sigrdatasetp = NULL; + if (WANTDNSSEC(client) && + (fname->attributes & DNS_NAMEATTR_WILDCARD) != 0) + { + dns_fixedname_init(&wildcardname); + dns_name_copy(fname, dns_fixedname_name(&wildcardname), + NULL); + need_wildcardproof = ISC_TRUE; + } + if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0 && + WANTDNSSEC(client)) + noqname = rdataset; + else + noqname = NULL; + query_addrrset(client, &fname, &rdataset, sigrdatasetp, dbuf, + DNS_SECTION_ANSWER); + if (noqname != NULL) + query_addnoqnameproof(client, noqname); + /* + * We set the PARTIALANSWER attribute so that if anything goes + * wrong later on, we'll return what we've got so far. + */ + client->query.attributes |= NS_QUERYATTR_PARTIALANSWER; + /* + * Reset qname to be the target name of the CNAME and restart + * the query. + */ + tname = NULL; + result = dns_message_gettempname(client->message, &tname); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_rdataset_first(trdataset); + if (result != ISC_R_SUCCESS) { + dns_message_puttempname(client->message, &tname); + goto cleanup; + } + dns_rdataset_current(trdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &cname, NULL); + dns_rdata_reset(&rdata); + if (result != ISC_R_SUCCESS) { + dns_message_puttempname(client->message, &tname); + goto cleanup; + } + dns_name_init(tname, NULL); + result = dns_name_dup(&cname.cname, client->mctx, tname); + if (result != ISC_R_SUCCESS) { + dns_message_puttempname(client->message, &tname); + dns_rdata_freestruct(&cname); + goto cleanup; + } + dns_rdata_freestruct(&cname); + ns_client_qnamereplace(client, tname); + want_restart = ISC_TRUE; + if (!WANTRECURSION(client)) + options |= DNS_GETDB_NOLOG; + goto addauth; + case DNS_R_DNAME: + /* + * Compare the current qname to the found name. We need + * to know how many labels and bits are in common because + * we're going to have to split qname later on. + */ + namereln = dns_name_fullcompare(client->query.qname, fname, + &order, &nlabels); + INSIST(namereln == dns_namereln_subdomain); + /* + * Keep a copy of the rdataset. We have to do this because + * query_addrrset may clear 'rdataset' (to prevent the + * cleanup code from cleaning it up). + */ + trdataset = rdataset; + /* + * Add the DNAME to the answer section. + */ + if (sigrdataset != NULL) + sigrdatasetp = &sigrdataset; + else + sigrdatasetp = NULL; + if (WANTDNSSEC(client) && + (fname->attributes & DNS_NAMEATTR_WILDCARD) != 0) + { + dns_fixedname_init(&wildcardname); + dns_name_copy(fname, dns_fixedname_name(&wildcardname), + NULL); + need_wildcardproof = ISC_TRUE; + } + query_addrrset(client, &fname, &rdataset, sigrdatasetp, dbuf, + DNS_SECTION_ANSWER); + /* + * We set the PARTIALANSWER attribute so that if anything goes + * wrong later on, we'll return what we've got so far. + */ + client->query.attributes |= NS_QUERYATTR_PARTIALANSWER; + /* + * Get the target name of the DNAME. + */ + tname = NULL; + result = dns_message_gettempname(client->message, &tname); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_rdataset_first(trdataset); + if (result != ISC_R_SUCCESS) { + dns_message_puttempname(client->message, &tname); + goto cleanup; + } + dns_rdataset_current(trdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &dname, NULL); + dns_rdata_reset(&rdata); + if (result != ISC_R_SUCCESS) { + dns_message_puttempname(client->message, &tname); + goto cleanup; + } + dns_name_init(tname, NULL); + dns_name_clone(&dname.dname, tname); + dns_rdata_freestruct(&dname); + /* + * Construct the new qname. + */ + dns_fixedname_init(&fixed); + prefix = dns_fixedname_name(&fixed); + dns_name_split(client->query.qname, nlabels, prefix, NULL); + INSIST(fname == NULL); + dbuf = query_getnamebuf(client); + if (dbuf == NULL) { + dns_message_puttempname(client->message, &tname); + goto cleanup; + } + fname = query_newname(client, dbuf, &b); + if (fname == NULL) { + dns_message_puttempname(client->message, &tname); + goto cleanup; + } + result = dns_name_concatenate(prefix, tname, fname, NULL); + if (result != ISC_R_SUCCESS) { + dns_message_puttempname(client->message, &tname); + if (result == ISC_R_NOSPACE) { + /* + * RFC2672, section 4.1, subsection 3c says + * we should return YXDOMAIN if the constructed + * name would be too long. + */ + client->message->rcode = dns_rcode_yxdomain; + } + goto cleanup; + } + query_keepname(client, fname, dbuf); + /* + * Synthesize a CNAME for this DNAME. + * + * We want to synthesize a CNAME since if we don't + * then older software that doesn't understand DNAME + * will not chain like it should. + * + * We do not try to synthesize a signature because we hope + * that security aware servers will understand DNAME. Also, + * even if we had an online key, making a signature + * on-the-fly is costly, and not really legitimate anyway + * since the synthesized CNAME is NOT in the zone. + */ + dns_name_init(tname, NULL); + (void)query_addcnamelike(client, client->query.qname, fname, + trdataset->trust, &tname, + dns_rdatatype_cname); + if (tname != NULL) + dns_message_puttempname(client->message, &tname); + /* + * Switch to the new qname and restart. + */ + ns_client_qnamereplace(client, fname); + fname = NULL; + want_restart = ISC_TRUE; + if (!WANTRECURSION(client)) + options |= DNS_GETDB_NOLOG; + goto addauth; + default: + /* + * Something has gone wrong. + */ + QUERY_ERROR(DNS_R_SERVFAIL); + goto cleanup; + } + + if (WANTDNSSEC(client) && + (fname->attributes & DNS_NAMEATTR_WILDCARD) != 0) + { + dns_fixedname_init(&wildcardname); + dns_name_copy(fname, dns_fixedname_name(&wildcardname), NULL); + need_wildcardproof = ISC_TRUE; + } + + if (type == dns_rdatatype_any) { + /* + * XXXRTH Need to handle zonecuts with special case + * code. + */ + n = 0; + rdsiter = NULL; + result = dns_db_allrdatasets(db, node, version, 0, &rdsiter); + if (result != ISC_R_SUCCESS) { + QUERY_ERROR(DNS_R_SERVFAIL); + goto cleanup; + } + /* + * Calling query_addrrset() with a non-NULL dbuf is going + * to either keep or release the name. We don't want it to + * release fname, since we may have to call query_addrrset() + * more than once. That means we have to call query_keepname() + * now, and pass a NULL dbuf to query_addrrset(). + * + * If we do a query_addrrset() below, we must set fname to + * NULL before leaving this block, otherwise we might try to + * cleanup fname even though we're using it! + */ + query_keepname(client, fname, dbuf); + tname = fname; + result = dns_rdatasetiter_first(rdsiter); + while (result == ISC_R_SUCCESS) { + dns_rdatasetiter_current(rdsiter, rdataset); + if ((qtype == dns_rdatatype_any || + rdataset->type == qtype) && rdataset->type != 0) { + query_addrrset(client, + fname != NULL ? &fname : &tname, + &rdataset, NULL, + NULL, DNS_SECTION_ANSWER); + n++; + INSIST(tname != NULL); + /* + * rdataset is non-NULL only in certain pathological + * cases involving DNAMEs. + */ + if (rdataset != NULL) + query_putrdataset(client, &rdataset); + rdataset = query_newrdataset(client); + if (rdataset == NULL) + break; + } else { + /* + * We're not interested in this rdataset. + */ + dns_rdataset_disassociate(rdataset); + } + result = dns_rdatasetiter_next(rdsiter); + } + + if (fname != NULL) + dns_message_puttempname(client->message, &fname); + + if (n == 0) { + /* + * We didn't match any rdatasets. + */ + if (qtype == dns_rdatatype_rrsig && + result == ISC_R_NOMORE) { + /* + * XXXRTH If this is a secure zone and we + * didn't find any SIGs, we should generate + * an error unless we were searching for + * glue. Ugh. + */ + if (!is_zone) { + authoritative = ISC_FALSE; + dns_rdatasetiter_destroy(&rdsiter); + if (RECURSIONOK(client)) { + result = query_recurse(client, + qtype, + NULL, + NULL, + resuming); + if (result == ISC_R_SUCCESS) + client->query.attributes |= + NS_QUERYATTR_RECURSING; + else + QUERY_ERROR(DNS_R_SERVFAIL); } + goto addauth; + } + /* + * We were searching for SIG records in + * a nonsecure zone. Send a "no error, + * no data" response. + */ + /* + * Add SOA. + */ + result = query_addsoa(client, db, version, + ISC_FALSE); + if (result == ISC_R_SUCCESS) + result = ISC_R_NOMORE; + } else { + /* + * Something went wrong. + */ + result = DNS_R_SERVFAIL; + } + } + dns_rdatasetiter_destroy(&rdsiter); + if (result != ISC_R_NOMORE) { + QUERY_ERROR(DNS_R_SERVFAIL); + goto cleanup; + } + } else { + /* + * This is the "normal" case -- an ordinary question to which + * we know the answer. + */ + if (sigrdataset != NULL) + sigrdatasetp = &sigrdataset; + else + sigrdatasetp = NULL; + if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0 && + WANTDNSSEC(client)) + noqname = rdataset; + else + noqname = NULL; + /* + * BIND 8 priming queries need the additional section. + */ + if (is_zone && qtype == dns_rdatatype_ns && + dns_name_equal(client->query.qname, dns_rootname)) + client->query.attributes &= ~NS_QUERYATTR_NOADDITIONAL; + + query_addrrset(client, &fname, &rdataset, sigrdatasetp, dbuf, + DNS_SECTION_ANSWER); + if (noqname != NULL) + query_addnoqnameproof(client, noqname); + /* + * We shouldn't ever fail to add 'rdataset' + * because it's already in the answer. + */ + INSIST(rdataset == NULL); + } + + addauth: + CTRACE("query_find: addauth"); + /* + * Add NS records to the authority section (if we haven't already + * added them to the answer section). + */ + if (!want_restart && !NOAUTHORITY(client)) { + if (is_zone) { + if (!((qtype == dns_rdatatype_ns || + qtype == dns_rdatatype_any) && + dns_name_equal(client->query.qname, + dns_db_origin(db)))) + (void)query_addns(client, db, version); + } else if (qtype != dns_rdatatype_ns) { + if (fname != NULL) + query_releasename(client, &fname); + query_addbestns(client); + } + } + + /* + * Add NSEC records to the authority section if they're needed for + * DNSSEC wildcard proofs. + */ + if (need_wildcardproof && dns_db_issecure(db)) + query_addwildcardproof(client, db, version, + dns_fixedname_name(&wildcardname), + ISC_TRUE); + cleanup: + CTRACE("query_find: cleanup"); + /* + * General cleanup. + */ + if (rdataset != NULL) + query_putrdataset(client, &rdataset); + if (sigrdataset != NULL) + query_putrdataset(client, &sigrdataset); + if (fname != NULL) + query_releasename(client, &fname); + if (node != NULL) + dns_db_detachnode(db, &node); + if (db != NULL) + dns_db_detach(&db); + if (zone != NULL) + dns_zone_detach(&zone); + if (zdb != NULL) { + query_putrdataset(client, &zrdataset); + if (zsigrdataset != NULL) + query_putrdataset(client, &zsigrdataset); + if (zfname != NULL) + query_releasename(client, &zfname); + dns_db_detach(&zdb); + } + if (event != NULL) + isc_event_free(ISC_EVENT_PTR(&event)); + + /* + * AA bit. + */ + if (client->query.restarts == 0 && !authoritative) { + /* + * We're not authoritative, so we must ensure the AA bit + * isn't set. + */ + client->message->flags &= ~DNS_MESSAGEFLAG_AA; + } + + /* + * Restart the query? + */ + if (want_restart && client->query.restarts < MAX_RESTARTS) { + client->query.restarts++; + goto restart; + } + + if (eresult != ISC_R_SUCCESS && + (!PARTIALANSWER(client) || WANTRECURSION(client))) { + if (eresult == DNS_R_DUPLICATE || eresult == DNS_R_DROP) { + /* + * This was a duplicate query that we are + * recursing on. Don't send a response now. + * The original query will still cause a response. + */ + query_next(client, eresult); + } else { + /* + * If we don't have any answer to give the client, + * or if the client requested recursion and thus wanted + * the complete answer, send an error response. + */ + INSIST(line >= 0); + query_error(client, eresult, line); + } + ns_client_detach(&client); + } else if (!RECURSING(client)) { + /* + * We are done. Set up sortlist data for the message + * rendering code, make a final tweak to the AA bit if the + * auth-nxdomain config option says so, then render and + * send the response. + */ + setup_query_sortlist(client); + + /* + * If this is a referral and the answer to the question + * is in the glue sort it to the start of the additional + * section. + */ + if (ISC_LIST_EMPTY(client->message->sections[DNS_SECTION_ANSWER]) && + client->message->rcode == dns_rcode_noerror && + (qtype == dns_rdatatype_a || qtype == dns_rdatatype_aaaa)) + answer_in_glue(client, qtype); + + if (client->message->rcode == dns_rcode_nxdomain && + client->view->auth_nxdomain == ISC_TRUE) + client->message->flags |= DNS_MESSAGEFLAG_AA; + + /* + * If the response is somehow unexpected for the client and this + * is a result of recursion, return an error to the caller + * to indicate it may need to be logged. + */ + if (resuming && + (ISC_LIST_EMPTY(client->message->sections[DNS_SECTION_ANSWER]) || + client->message->rcode != dns_rcode_noerror)) + eresult = ISC_R_FAILURE; + + query_send(client); + ns_client_detach(&client); + } + CTRACE("query_find: done"); + + return (eresult); +} + +static inline void +log_query(ns_client_t *client, unsigned int flags, unsigned int extflags) { + char namebuf[DNS_NAME_FORMATSIZE]; + char typename[DNS_RDATATYPE_FORMATSIZE]; + char classname[DNS_RDATACLASS_FORMATSIZE]; + dns_rdataset_t *rdataset; + int level = ISC_LOG_INFO; + + if (! isc_log_wouldlog(ns_g_lctx, level)) + return; + + rdataset = ISC_LIST_HEAD(client->query.qname->list); + INSIST(rdataset != NULL); + dns_name_format(client->query.qname, namebuf, sizeof(namebuf)); + dns_rdataclass_format(rdataset->rdclass, classname, sizeof(classname)); + dns_rdatatype_format(rdataset->type, typename, sizeof(typename)); + + ns_client_log(client, NS_LOGCATEGORY_QUERIES, NS_LOGMODULE_QUERY, + level, "query: %s %s %s %s%s%s%s%s", namebuf, classname, + typename, WANTRECURSION(client) ? "+" : "-", + (client->signer != NULL) ? "S": "", + (client->opt != NULL) ? "E" : "", + ((extflags & DNS_MESSAGEEXTFLAG_DO) != 0) ? "D" : "", + ((flags & DNS_MESSAGEFLAG_CD) != 0) ? "C" : ""); +} + +static inline void +log_queryerror(ns_client_t *client, isc_result_t result, int line, int level) { + char namebuf[DNS_NAME_FORMATSIZE]; + char typename[DNS_RDATATYPE_FORMATSIZE]; + char classname[DNS_RDATACLASS_FORMATSIZE]; + const char *namep, *typep, *classp, *sep1, *sep2; + dns_rdataset_t *rdataset; + + if (!isc_log_wouldlog(ns_g_lctx, level)) + return; + + namep = typep = classp = sep1 = sep2 = ""; + + /* + * Query errors can happen for various reasons. In some cases we cannot + * even assume the query contains a valid question section, so we should + * expect exceptional cases. + */ + if (client->query.origqname != NULL) { + dns_name_format(client->query.origqname, namebuf, + sizeof(namebuf)); + namep = namebuf; + sep1 = " for "; + + rdataset = ISC_LIST_HEAD(client->query.origqname->list); + if (rdataset != NULL) { + dns_rdataclass_format(rdataset->rdclass, classname, + sizeof(classname)); + classp = classname; + dns_rdatatype_format(rdataset->type, typename, + sizeof(typename)); + typep = typename; + sep2 = "/"; + } + } + + ns_client_log(client, NS_LOGCATEGORY_QUERY_EERRORS, NS_LOGMODULE_QUERY, + level, "query failed (%s)%s%s%s%s%s%s at %s:%d", + isc_result_totext(result), sep1, namep, sep2, + classp, sep2, typep, __FILE__, line); +} + +void +ns_query_start(ns_client_t *client) { + isc_result_t result; + dns_message_t *message = client->message; + dns_rdataset_t *rdataset; + ns_client_t *qclient; + dns_rdatatype_t qtype; + unsigned int saved_extflags = client->extflags; + unsigned int saved_flags = client->message->flags; + isc_boolean_t want_ad; + + CTRACE("ns_query_start"); + + /* + * Ensure that appropriate cleanups occur. + */ + client->next = query_next_callback; + + /* + * Behave as if we don't support DNSSEC if not enabled. + */ + if (!client->view->enablednssec) { + message->flags &= ~DNS_MESSAGEFLAG_CD; + client->extflags &= ~DNS_MESSAGEEXTFLAG_DO; + if (client->opt != NULL) + client->opt->ttl &= ~DNS_MESSAGEEXTFLAG_DO; + } + + if ((message->flags & DNS_MESSAGEFLAG_RD) != 0) + client->query.attributes |= NS_QUERYATTR_WANTRECURSION; + + if ((client->extflags & DNS_MESSAGEEXTFLAG_DO) != 0) + client->attributes |= NS_CLIENTATTR_WANTDNSSEC; + + if (client->view->minimalresponses) + client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY | + NS_QUERYATTR_NOADDITIONAL); + + if ((client->view->cachedb == NULL) + || (!client->view->additionalfromcache)) { + /* + * We don't have a cache. Turn off cache support and + * recursion. + */ + client->query.attributes &= + ~(NS_QUERYATTR_RECURSIONOK|NS_QUERYATTR_CACHEOK); + } else if ((client->attributes & NS_CLIENTATTR_RA) == 0 || + (message->flags & DNS_MESSAGEFLAG_RD) == 0) { + /* + * If the client isn't allowed to recurse (due to + * "recursion no", the allow-recursion ACL, or the + * lack of a resolver in this view), or if it + * doesn't want recursion, turn recursion off. + */ + client->query.attributes &= ~NS_QUERYATTR_RECURSIONOK; + } + + /* + * Get the question name. + */ + result = dns_message_firstname(message, DNS_SECTION_QUESTION); + if (result != ISC_R_SUCCESS) { + query_error(client, result, __LINE__); + return; + } + dns_message_currentname(message, DNS_SECTION_QUESTION, + &client->query.qname); + client->query.origqname = client->query.qname; + result = dns_message_nextname(message, DNS_SECTION_QUESTION); + if (result != ISC_R_NOMORE) { + if (result == ISC_R_SUCCESS) { + /* + * There's more than one QNAME in the question + * section. + */ + query_error(client, DNS_R_FORMERR, __LINE__); + } else + query_error(client, result, __LINE__); + return; + } + + if (ns_g_server->log_queries) + log_query(client, saved_flags, saved_extflags); + + /* + * Check for multiple question queries, since edns1 is dead. + */ + if (message->counts[DNS_SECTION_QUESTION] > 1) { + query_error(client, DNS_R_FORMERR, __LINE__); + return; + } + + /* + * Check for meta-queries like IXFR and AXFR. + */ + rdataset = ISC_LIST_HEAD(client->query.qname->list); + INSIST(rdataset != NULL); + qtype = rdataset->type; + dns_rdatatypestats_increment(ns_g_server->rcvquerystats, qtype); + if (dns_rdatatype_ismeta(qtype)) { + switch (qtype) { + case dns_rdatatype_any: + break; /* Let query_find handle it. */ + case dns_rdatatype_ixfr: + case dns_rdatatype_axfr: + ns_xfr_start(client, rdataset->type); + return; + case dns_rdatatype_maila: + case dns_rdatatype_mailb: + query_error(client, DNS_R_NOTIMP, __LINE__); + return; + case dns_rdatatype_tkey: + result = dns_tkey_processquery(client->message, + ns_g_server->tkeyctx, + client->view->dynamickeys); + if (result == ISC_R_SUCCESS) + query_send(client); + else + query_error(client, result, __LINE__); + return; + default: /* TSIG, etc. */ + query_error(client, DNS_R_FORMERR, __LINE__); + return; + } + } + + /* + * Turn on minimal response for DNSKEY and DS queries. + */ + if (qtype == dns_rdatatype_dnskey || qtype == dns_rdatatype_ds) + client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY | + NS_QUERYATTR_NOADDITIONAL); + + /* + * If the client has requested that DNSSEC checking be disabled, + * allow lookups to return pending data and instruct the resolver + * to return data before validation has completed. + * + * We don't need to set DNS_DBFIND_PENDINGOK when validation is + * disabled as there will be no pending data. + */ + if (message->flags & DNS_MESSAGEFLAG_CD || + qtype == dns_rdatatype_rrsig) + { + client->query.dboptions |= DNS_DBFIND_PENDINGOK; + client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE; + } else if (!client->view->enablevalidation) + client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE; + + /* + * Allow glue NS records to be added to the authority section + * if the answer is secure. + */ + if (message->flags & DNS_MESSAGEFLAG_CD) + client->query.attributes &= ~NS_QUERYATTR_SECURE; + + /* + * Set 'want_ad' if the client has set AD in the query. + * This allows AD to be returned on queries without DO set. + */ + if ((message->flags & DNS_MESSAGEFLAG_AD) != 0) + want_ad = ISC_TRUE; + else + want_ad = ISC_FALSE; + + /* + * This is an ordinary query. + */ + result = dns_message_reply(message, ISC_TRUE); + if (result != ISC_R_SUCCESS) { + query_next(client, result); + return; + } + + /* + * Assume authoritative response until it is known to be + * otherwise. + */ + message->flags |= DNS_MESSAGEFLAG_AA; + + /* + * Set AD. We must clear it if we add non-validated data to a + * response. + */ + if (WANTDNSSEC(client) || want_ad) + message->flags |= DNS_MESSAGEFLAG_AD; + + qclient = NULL; + ns_client_attach(client, &qclient); + (void)query_find(qclient, NULL, qtype); +} diff --git a/contrib/bind-9.5.2/bin/named/server.c b/contrib/bind-9.5.2/bin/named/server.c new file mode 100644 index 0000000000..d3fdb01444 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/server.c @@ -0,0 +1,5522 @@ +/* + * Copyright (C) 2004-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 + * 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: server.c,v 1.495.10.29 2009/07/11 04:28:14 marka Exp $ */ + +/*! \file */ + +#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 +#ifdef DLZ +#include +#endif +#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 +#include +#include +#include +#include +#include +#ifdef HAVE_LIBSCF +#include +#include +#endif + +/*% + * Check an operation for failure. Assumes that the function + * using it has a 'result' variable and a 'cleanup' label. + */ +#define CHECK(op) \ + do { result = (op); \ + if (result != ISC_R_SUCCESS) goto cleanup; \ + } while (0) + +#define CHECKM(op, msg) \ + do { result = (op); \ + if (result != ISC_R_SUCCESS) { \ + isc_log_write(ns_g_lctx, \ + NS_LOGCATEGORY_GENERAL, \ + NS_LOGMODULE_SERVER, \ + ISC_LOG_ERROR, \ + "%s: %s", msg, \ + isc_result_totext(result)); \ + goto cleanup; \ + } \ + } while (0) \ + +#define CHECKMF(op, msg, file) \ + do { result = (op); \ + if (result != ISC_R_SUCCESS) { \ + isc_log_write(ns_g_lctx, \ + NS_LOGCATEGORY_GENERAL, \ + NS_LOGMODULE_SERVER, \ + ISC_LOG_ERROR, \ + "%s '%s': %s", msg, file, \ + isc_result_totext(result)); \ + goto cleanup; \ + } \ + } while (0) \ + +#define CHECKFATAL(op, msg) \ + do { result = (op); \ + if (result != ISC_R_SUCCESS) \ + fatal(msg, result); \ + } while (0) \ + +struct ns_dispatch { + isc_sockaddr_t addr; + unsigned int dispatchgen; + dns_dispatch_t *dispatch; + ISC_LINK(struct ns_dispatch) link; +}; + +struct dumpcontext { + isc_mem_t *mctx; + isc_boolean_t dumpcache; + isc_boolean_t dumpzones; + FILE *fp; + ISC_LIST(struct viewlistentry) viewlist; + struct viewlistentry *view; + struct zonelistentry *zone; + dns_dumpctx_t *mdctx; + dns_db_t *db; + dns_db_t *cache; + isc_task_t *task; + dns_dbversion_t *version; +}; + +struct viewlistentry { + dns_view_t *view; + ISC_LINK(struct viewlistentry) link; + ISC_LIST(struct zonelistentry) zonelist; +}; + +struct zonelistentry { + dns_zone_t *zone; + ISC_LINK(struct zonelistentry) link; +}; + +/* + * These zones should not leak onto the Internet. + */ +static const struct { + const char *zone; + isc_boolean_t rfc1918; +} empty_zones[] = { +#ifdef notyet + /* RFC 1918 */ + { "10.IN-ADDR.ARPA", ISC_TRUE }, + { "16.172.IN-ADDR.ARPA", ISC_TRUE }, + { "17.172.IN-ADDR.ARPA", ISC_TRUE }, + { "18.172.IN-ADDR.ARPA", ISC_TRUE }, + { "19.172.IN-ADDR.ARPA", ISC_TRUE }, + { "20.172.IN-ADDR.ARPA", ISC_TRUE }, + { "21.172.IN-ADDR.ARPA", ISC_TRUE }, + { "22.172.IN-ADDR.ARPA", ISC_TRUE }, + { "23.172.IN-ADDR.ARPA", ISC_TRUE }, + { "24.172.IN-ADDR.ARPA", ISC_TRUE }, + { "25.172.IN-ADDR.ARPA", ISC_TRUE }, + { "26.172.IN-ADDR.ARPA", ISC_TRUE }, + { "27.172.IN-ADDR.ARPA", ISC_TRUE }, + { "28.172.IN-ADDR.ARPA", ISC_TRUE }, + { "29.172.IN-ADDR.ARPA", ISC_TRUE }, + { "30.172.IN-ADDR.ARPA", ISC_TRUE }, + { "31.172.IN-ADDR.ARPA", ISC_TRUE }, + { "168.192.IN-ADDR.ARPA", ISC_TRUE }, +#endif + + /* RFC 3330 */ + { "0.IN-ADDR.ARPA", ISC_FALSE }, /* THIS NETWORK */ + { "127.IN-ADDR.ARPA", ISC_FALSE }, /* LOOPBACK */ + { "254.169.IN-ADDR.ARPA", ISC_FALSE }, /* LINK LOCAL */ + { "2.0.192.IN-ADDR.ARPA", ISC_FALSE }, /* TEST NET */ + { "255.255.255.255.IN-ADDR.ARPA", ISC_FALSE }, /* BROADCAST */ + + /* Local IPv6 Unicast Addresses */ + { "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA", ISC_FALSE }, + { "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA", ISC_FALSE }, + /* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */ + { "D.F.IP6.ARPA", ISC_FALSE }, + { "8.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ + { "9.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ + { "A.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ + { "B.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ + + { NULL, ISC_FALSE } +}; + +static void +fatal(const char *msg, isc_result_t result); + +static void +ns_server_reload(isc_task_t *task, isc_event_t *event); + +static isc_result_t +ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, + cfg_aclconfctx_t *actx, + isc_mem_t *mctx, ns_listenelt_t **target); +static isc_result_t +ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config, + cfg_aclconfctx_t *actx, + isc_mem_t *mctx, ns_listenlist_t **target); + +static isc_result_t +configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, + const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype); + +static isc_result_t +configure_alternates(const cfg_obj_t *config, dns_view_t *view, + const cfg_obj_t *alternates); + +static isc_result_t +configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, + const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, + cfg_aclconfctx_t *aclconf); + +static void +end_reserved_dispatches(ns_server_t *server, isc_boolean_t all); + +/*% + * Configure a single view ACL at '*aclp'. Get its configuration from + * 'vconfig' (for per-view configuration) and maybe from 'config' + */ +static isc_result_t +configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config, + const char *aclname, cfg_aclconfctx_t *actx, + isc_mem_t *mctx, dns_acl_t **aclp) +{ + isc_result_t result; + const cfg_obj_t *maps[3]; + const cfg_obj_t *aclobj = NULL; + int i = 0; + + if (*aclp != NULL) + dns_acl_detach(aclp); + if (vconfig != NULL) + maps[i++] = cfg_tuple_get(vconfig, "options"); + if (config != NULL) { + const cfg_obj_t *options = NULL; + (void)cfg_map_get(config, "options", &options); + if (options != NULL) + maps[i++] = options; + } + maps[i] = NULL; + + (void)ns_config_get(maps, aclname, &aclobj); + if (aclobj == NULL) + /* + * No value available. *aclp == NULL. + */ + return (ISC_R_SUCCESS); + + result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx, + actx, mctx, 0, aclp); + + return (result); +} + + +/*% + * Configure a sortlist at '*aclp'. Essentially the same as + * configure_view_acl() except it calls cfg_acl_fromconfig with a + * nest_level value of 2. + */ +static isc_result_t +configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config, + cfg_aclconfctx_t *actx, isc_mem_t *mctx, + dns_acl_t **aclp) +{ + isc_result_t result; + const cfg_obj_t *maps[3]; + const cfg_obj_t *aclobj = NULL; + int i = 0; + + if (*aclp != NULL) + dns_acl_detach(aclp); + if (vconfig != NULL) + maps[i++] = cfg_tuple_get(vconfig, "options"); + if (config != NULL) { + const cfg_obj_t *options = NULL; + (void)cfg_map_get(config, "options", &options); + if (options != NULL) + maps[i++] = options; + } + maps[i] = NULL; + + (void)ns_config_get(maps, "sortlist", &aclobj); + if (aclobj == NULL) + return (ISC_R_SUCCESS); + + /* + * Use a nest level of 3 for the "top level" of the sortlist; + * this means each entry in the top three levels will be stored + * as lists of separate, nested ACLs, rather than merged together + * into IP tables as is usually done with ACLs. + */ + result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx, + actx, mctx, 3, aclp); + + return (result); +} + +static isc_result_t +configure_view_dnsseckey(const cfg_obj_t *vconfig, const cfg_obj_t *key, + dns_keytable_t *keytable, isc_mem_t *mctx) +{ + dns_rdataclass_t viewclass; + dns_rdata_dnskey_t keystruct; + isc_uint32_t flags, proto, alg; + const char *keystr, *keynamestr; + unsigned char keydata[4096]; + isc_buffer_t keydatabuf; + unsigned char rrdata[4096]; + isc_buffer_t rrdatabuf; + isc_region_t r; + dns_fixedname_t fkeyname; + dns_name_t *keyname; + isc_buffer_t namebuf; + isc_result_t result; + dst_key_t *dstkey = NULL; + + 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")); + keyname = dns_fixedname_name(&fkeyname); + keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name")); + + if (vconfig == NULL) + viewclass = dns_rdataclass_in; + else { + const cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class"); + CHECK(ns_config_getclass(classobj, dns_rdataclass_in, + &viewclass)); + } + keystruct.common.rdclass = viewclass; + keystruct.common.rdtype = dns_rdatatype_dnskey; + /* + * The key data in keystruct is not dynamically allocated. + */ + keystruct.mctx = NULL; + + ISC_LINK_INIT(&keystruct.common, link); + + if (flags > 0xffff) + CHECKM(ISC_R_RANGE, "key flags"); + if (proto > 0xff) + CHECKM(ISC_R_RANGE, "key protocol"); + if (alg > 0xff) + CHECKM(ISC_R_RANGE, "key algorithm"); + keystruct.flags = (isc_uint16_t)flags; + keystruct.protocol = (isc_uint8_t)proto; + keystruct.algorithm = (isc_uint8_t)alg; + + isc_buffer_init(&keydatabuf, keydata, sizeof(keydata)); + isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata)); + + keystr = cfg_obj_asstring(cfg_tuple_get(key, "key")); + CHECK(isc_base64_decodestring(keystr, &keydatabuf)); + isc_buffer_usedregion(&keydatabuf, &r); + keystruct.datalen = r.length; + keystruct.data = r.base; + + if ((keystruct.algorithm == DST_ALG_RSASHA1 || + keystruct.algorithm == DST_ALG_RSAMD5) && + r.length > 1 && r.base[0] == 1 && r.base[1] == 3) + cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, + "trusted key '%s' has a weak exponent", + keynamestr); + + CHECK(dns_rdata_fromstruct(NULL, + keystruct.common.rdclass, + keystruct.common.rdtype, + &keystruct, &rrdatabuf)); + dns_fixedname_init(&fkeyname); + isc_buffer_init(&namebuf, keynamestr, strlen(keynamestr)); + isc_buffer_add(&namebuf, strlen(keynamestr)); + CHECK(dns_name_fromtext(keyname, &namebuf, + dns_rootname, ISC_FALSE, + NULL)); + CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf, + mctx, &dstkey)); + + CHECK(dns_keytable_add(keytable, &dstkey)); + INSIST(dstkey == NULL); + return (ISC_R_SUCCESS); + + cleanup: + if (result == DST_R_NOCRYPTO) { + cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR, + "ignoring trusted key for '%s': no crypto support", + keynamestr); + result = ISC_R_SUCCESS; + } else { + cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR, + "configuring trusted key for '%s': %s", + keynamestr, isc_result_totext(result)); + result = ISC_R_FAILURE; + } + + if (dstkey != NULL) + dst_key_free(&dstkey); + + return (result); +} + +/*% + * Configure DNSSEC keys for a view. Currently used only for + * the security roots. + * + * The per-view configuration values and the server-global defaults are read + * from 'vconfig' and 'config'. The variable to be configured is '*target'. + */ +static isc_result_t +configure_view_dnsseckeys(const cfg_obj_t *vconfig, const cfg_obj_t *config, + isc_mem_t *mctx, dns_keytable_t **target) +{ + isc_result_t result; + const cfg_obj_t *keys = NULL; + const cfg_obj_t *voptions = NULL; + const cfg_listelt_t *element, *element2; + const cfg_obj_t *keylist; + const cfg_obj_t *key; + dns_keytable_t *keytable = NULL; + + CHECK(dns_keytable_create(mctx, &keytable)); + + if (vconfig != NULL) + voptions = cfg_tuple_get(vconfig, "options"); + + keys = NULL; + if (voptions != NULL) + (void)cfg_map_get(voptions, "trusted-keys", &keys); + if (keys == NULL) + (void)cfg_map_get(config, "trusted-keys", &keys); + + 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)) + { + key = cfg_listelt_value(element2); + CHECK(configure_view_dnsseckey(vconfig, key, + keytable, mctx)); + } + } + + dns_keytable_detach(target); + *target = keytable; /* Transfer ownership. */ + keytable = NULL; + result = ISC_R_SUCCESS; + + cleanup: + return (result); +} + +static isc_result_t +mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) +{ + const cfg_listelt_t *element; + const cfg_obj_t *obj; + const char *str; + dns_fixedname_t fixed; + dns_name_t *name; + isc_boolean_t value; + isc_result_t result; + isc_buffer_t b; + + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + for (element = cfg_list_first(mbs); + element != NULL; + element = cfg_list_next(element)) + { + obj = cfg_listelt_value(element); + str = cfg_obj_asstring(cfg_tuple_get(obj, "name")); + isc_buffer_init(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + CHECK(dns_name_fromtext(name, &b, dns_rootname, + ISC_FALSE, NULL)); + value = cfg_obj_asboolean(cfg_tuple_get(obj, "value")); + CHECK(dns_resolver_setmustbesecure(resolver, name, value)); + } + + result = ISC_R_SUCCESS; + + cleanup: + return (result); +} + +/*% + * Get a dispatch appropriate for the resolver of a given view. + */ +static isc_result_t +get_view_querysource_dispatch(const cfg_obj_t **maps, + int af, dns_dispatch_t **dispatchp, + isc_boolean_t is_firstview) +{ + isc_result_t result; + dns_dispatch_t *disp; + isc_sockaddr_t sa; + unsigned int attrs, attrmask; + const cfg_obj_t *obj = NULL; + unsigned int maxdispatchbuffers; + + /* + * Make compiler happy. + */ + result = ISC_R_FAILURE; + + switch (af) { + case AF_INET: + result = ns_config_get(maps, "query-source", &obj); + INSIST(result == ISC_R_SUCCESS); + break; + case AF_INET6: + result = ns_config_get(maps, "query-source-v6", &obj); + INSIST(result == ISC_R_SUCCESS); + break; + default: + INSIST(0); + } + + sa = *(cfg_obj_assockaddr(obj)); + INSIST(isc_sockaddr_pf(&sa) == af); + + /* + * If we don't support this address family, we're done! + */ + switch (af) { + case AF_INET: + result = isc_net_probeipv4(); + break; + case AF_INET6: + result = isc_net_probeipv6(); + break; + default: + INSIST(0); + } + if (result != ISC_R_SUCCESS) + return (ISC_R_SUCCESS); + + /* + * Try to find a dispatcher that we can share. + */ + attrs = 0; + attrs |= DNS_DISPATCHATTR_UDP; + switch (af) { + case AF_INET: + attrs |= DNS_DISPATCHATTR_IPV4; + break; + case AF_INET6: + attrs |= DNS_DISPATCHATTR_IPV6; + break; + } + if (isc_sockaddr_getport(&sa) == 0) { + attrs |= DNS_DISPATCHATTR_EXCLUSIVE; + maxdispatchbuffers = 4096; + } else { + INSIST(obj != NULL); + if (is_firstview) { + cfg_obj_log(obj, ns_g_lctx, ISC_LOG_INFO, + "using specific query-source port " + "suppresses port randomization and can be " + "insecure."); + } + maxdispatchbuffers = 1000; + } + + attrmask = 0; + attrmask |= DNS_DISPATCHATTR_UDP; + attrmask |= DNS_DISPATCHATTR_TCP; + attrmask |= DNS_DISPATCHATTR_IPV4; + attrmask |= DNS_DISPATCHATTR_IPV6; + + disp = NULL; + result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr, + ns_g_taskmgr, &sa, 4096, + maxdispatchbuffers, 32768, 16411, 16433, + attrs, attrmask, &disp); + if (result != ISC_R_SUCCESS) { + isc_sockaddr_t any; + char buf[ISC_SOCKADDR_FORMATSIZE]; + + switch (af) { + case AF_INET: + isc_sockaddr_any(&any); + break; + case AF_INET6: + isc_sockaddr_any6(&any); + break; + } + if (isc_sockaddr_equal(&sa, &any)) + return (ISC_R_SUCCESS); + isc_sockaddr_format(&sa, buf, sizeof(buf)); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "could not get query source dispatcher (%s)", + buf); + return (result); + } + + *dispatchp = disp; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +configure_order(dns_order_t *order, const cfg_obj_t *ent) { + dns_rdataclass_t rdclass; + dns_rdatatype_t rdtype; + const cfg_obj_t *obj; + dns_fixedname_t fixed; + unsigned int mode = 0; + const char *str; + isc_buffer_t b; + isc_result_t result; + isc_boolean_t addroot; + + result = ns_config_getclass(cfg_tuple_get(ent, "class"), + dns_rdataclass_any, &rdclass); + if (result != ISC_R_SUCCESS) + return (result); + + result = ns_config_gettype(cfg_tuple_get(ent, "type"), + dns_rdatatype_any, &rdtype); + if (result != ISC_R_SUCCESS) + return (result); + + obj = cfg_tuple_get(ent, "name"); + if (cfg_obj_isstring(obj)) + str = cfg_obj_asstring(obj); + else + str = "*"; + addroot = ISC_TF(strcmp(str, "*") == 0); + isc_buffer_init(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + dns_fixedname_init(&fixed); + result = dns_name_fromtext(dns_fixedname_name(&fixed), &b, + dns_rootname, ISC_FALSE, NULL); + if (result != ISC_R_SUCCESS) + return (result); + + obj = cfg_tuple_get(ent, "ordering"); + INSIST(cfg_obj_isstring(obj)); + str = cfg_obj_asstring(obj); + if (!strcasecmp(str, "fixed")) + mode = DNS_RDATASETATTR_FIXEDORDER; + else if (!strcasecmp(str, "random")) + mode = DNS_RDATASETATTR_RANDOMIZE; + else if (!strcasecmp(str, "cyclic")) + mode = 0; + else + INSIST(0); + + /* + * "*" should match everything including the root (BIND 8 compat). + * As dns_name_matcheswildcard(".", "*.") returns FALSE add a + * explicit entry for "." when the name is "*". + */ + if (addroot) { + result = dns_order_add(order, dns_rootname, + rdtype, rdclass, mode); + if (result != ISC_R_SUCCESS) + return (result); + } + + return (dns_order_add(order, dns_fixedname_name(&fixed), + rdtype, rdclass, mode)); +} + +static isc_result_t +configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) { + isc_netaddr_t na; + dns_peer_t *peer; + const cfg_obj_t *obj; + const char *str; + isc_result_t result; + unsigned int prefixlen; + + cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen); + + peer = NULL; + result = dns_peer_newprefix(mctx, &na, prefixlen, &peer); + if (result != ISC_R_SUCCESS) + return (result); + + obj = NULL; + (void)cfg_map_get(cpeer, "bogus", &obj); + if (obj != NULL) + CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj))); + + obj = NULL; + (void)cfg_map_get(cpeer, "provide-ixfr", &obj); + if (obj != NULL) + CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj))); + + obj = NULL; + (void)cfg_map_get(cpeer, "request-ixfr", &obj); + if (obj != NULL) + CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj))); + + obj = NULL; + (void)cfg_map_get(cpeer, "request-nsid", &obj); + if (obj != NULL) + CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj))); + + obj = NULL; + (void)cfg_map_get(cpeer, "edns", &obj); + if (obj != NULL) + CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj))); + + obj = NULL; + (void)cfg_map_get(cpeer, "edns-udp-size", &obj); + if (obj != NULL) { + isc_uint32_t udpsize = cfg_obj_asuint32(obj); + if (udpsize < 512) + udpsize = 512; + if (udpsize > 4096) + udpsize = 4096; + CHECK(dns_peer_setudpsize(peer, (isc_uint16_t)udpsize)); + } + + obj = NULL; + (void)cfg_map_get(cpeer, "max-udp-size", &obj); + if (obj != NULL) { + isc_uint32_t udpsize = cfg_obj_asuint32(obj); + if (udpsize < 512) + udpsize = 512; + if (udpsize > 4096) + udpsize = 4096; + CHECK(dns_peer_setmaxudp(peer, (isc_uint16_t)udpsize)); + } + + obj = NULL; + (void)cfg_map_get(cpeer, "transfers", &obj); + if (obj != NULL) + CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj))); + + obj = NULL; + (void)cfg_map_get(cpeer, "transfer-format", &obj); + if (obj != NULL) { + str = cfg_obj_asstring(obj); + if (strcasecmp(str, "many-answers") == 0) + CHECK(dns_peer_settransferformat(peer, + dns_many_answers)); + else if (strcasecmp(str, "one-answer") == 0) + CHECK(dns_peer_settransferformat(peer, + dns_one_answer)); + else + INSIST(0); + } + + obj = NULL; + (void)cfg_map_get(cpeer, "keys", &obj); + if (obj != NULL) { + result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj)); + if (result != ISC_R_SUCCESS) + goto cleanup; + } + + obj = NULL; + if (na.family == AF_INET) + (void)cfg_map_get(cpeer, "transfer-source", &obj); + else + (void)cfg_map_get(cpeer, "transfer-source-v6", &obj); + if (obj != NULL) { + result = dns_peer_settransfersource(peer, + cfg_obj_assockaddr(obj)); + if (result != ISC_R_SUCCESS) + goto cleanup; + ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); + } + + obj = NULL; + if (na.family == AF_INET) + (void)cfg_map_get(cpeer, "notify-source", &obj); + else + (void)cfg_map_get(cpeer, "notify-source-v6", &obj); + if (obj != NULL) { + result = dns_peer_setnotifysource(peer, + cfg_obj_assockaddr(obj)); + if (result != ISC_R_SUCCESS) + goto cleanup; + ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); + } + + obj = NULL; + if (na.family == AF_INET) + (void)cfg_map_get(cpeer, "query-source", &obj); + else + (void)cfg_map_get(cpeer, "query-source-v6", &obj); + if (obj != NULL) { + result = dns_peer_setquerysource(peer, + cfg_obj_assockaddr(obj)); + if (result != ISC_R_SUCCESS) + goto cleanup; + ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); + } + + *peerp = peer; + return (ISC_R_SUCCESS); + + cleanup: + dns_peer_detach(&peer); + return (result); +} + +static isc_result_t +disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) { + isc_result_t result; + const cfg_obj_t *algorithms; + const cfg_listelt_t *element; + const char *str; + dns_fixedname_t fixed; + dns_name_t *name; + isc_buffer_t b; + + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + str = cfg_obj_asstring(cfg_tuple_get(disabled, "name")); + isc_buffer_init(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + CHECK(dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL)); + + algorithms = cfg_tuple_get(disabled, "algorithms"); + for (element = cfg_list_first(algorithms); + element != NULL; + element = cfg_list_next(element)) + { + isc_textregion_t r; + dns_secalg_t alg; + + DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base); + r.length = strlen(r.base); + + result = dns_secalg_fromtext(&alg, &r); + if (result != ISC_R_SUCCESS) { + isc_uint8_t ui; + result = isc_parse_uint8(&ui, r.base, 10); + alg = ui; + } + if (result != ISC_R_SUCCESS) { + cfg_obj_log(cfg_listelt_value(element), + ns_g_lctx, ISC_LOG_ERROR, + "invalid algorithm"); + CHECK(result); + } + CHECK(dns_resolver_disable_algorithm(resolver, name, alg)); + } + cleanup: + return (result); +} + +static isc_boolean_t +on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) { + const cfg_listelt_t *element; + dns_fixedname_t fixed; + dns_name_t *name; + isc_result_t result; + const cfg_obj_t *value; + const char *str; + isc_buffer_t b; + + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + + for (element = cfg_list_first(disablelist); + element != NULL; + element = cfg_list_next(element)) + { + value = cfg_listelt_value(element); + str = cfg_obj_asstring(value); + isc_buffer_init(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + result = dns_name_fromtext(name, &b, dns_rootname, + ISC_TRUE, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + if (dns_name_equal(name, zonename)) + return (ISC_TRUE); + } + return (ISC_FALSE); +} + +static void +check_dbtype(dns_zone_t **zonep, unsigned int dbtypec, const char **dbargv, + isc_mem_t *mctx) +{ + char **argv = NULL; + unsigned int i; + isc_result_t result; + + result = dns_zone_getdbtype(*zonep, &argv, mctx); + if (result != ISC_R_SUCCESS) { + dns_zone_detach(zonep); + return; + } + + /* + * Check that all the arguments match. + */ + for (i = 0; i < dbtypec; i++) + if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0) { + dns_zone_detach(zonep); + break; + } + + /* + * Check that there are not extra arguments. + */ + if (i == dbtypec && argv[i] != NULL) + dns_zone_detach(zonep); + isc_mem_free(mctx, argv); +} + +static isc_result_t +setquerystats(dns_zone_t *zone, isc_mem_t *mctx, isc_boolean_t on) { + isc_result_t result; + isc_stats_t *zoneqrystats; + + zoneqrystats = NULL; + if (on) { + result = isc_stats_create(mctx, &zoneqrystats, + dns_nsstatscounter_max); + if (result != ISC_R_SUCCESS) + return (result); + } + dns_zone_setrequeststats(zone, zoneqrystats); + if (zoneqrystats != NULL) + isc_stats_detach(&zoneqrystats); + + return (ISC_R_SUCCESS); +} + +static isc_boolean_t +cache_reusable(dns_view_t *originview, dns_view_t *view, + isc_boolean_t new_zero_no_soattl) +{ + if (originview->checknames != view->checknames || + dns_resolver_getzeronosoattl(originview->resolver) != + new_zero_no_soattl || + originview->acceptexpired != view->acceptexpired || + originview->enablevalidation != view->enablevalidation || + originview->maxcachettl != view->maxcachettl || + originview->maxncachettl != view->maxncachettl) { + return (ISC_FALSE); + } + + return (ISC_TRUE); +} + +/* + * Configure 'view' according to 'vconfig', taking defaults from 'config' + * where values are missing in 'vconfig'. + * + * When configuring the default view, 'vconfig' will be NULL and the + * global defaults in 'config' used exclusively. + */ +static isc_result_t +configure_view(dns_view_t *view, const cfg_obj_t *config, + const cfg_obj_t *vconfig, isc_mem_t *mctx, + cfg_aclconfctx_t *actx, isc_boolean_t need_hints) +{ + const cfg_obj_t *maps[4]; + const cfg_obj_t *cfgmaps[3]; + const cfg_obj_t *options = NULL; + const cfg_obj_t *voptions = NULL; + const cfg_obj_t *forwardtype; + const cfg_obj_t *forwarders; + const cfg_obj_t *alternates; + const cfg_obj_t *zonelist; +#ifdef DLZ + const cfg_obj_t *dlz; + unsigned int dlzargc; + char **dlzargv; +#endif + const cfg_obj_t *disabled; + const cfg_obj_t *obj; + const cfg_listelt_t *element; + in_port_t port; + dns_cache_t *cache = NULL; + isc_result_t result; + isc_uint32_t max_adb_size; + isc_uint32_t max_cache_size; + isc_uint32_t max_acache_size; + isc_uint32_t lame_ttl; + dns_tsig_keyring_t *ring; + dns_view_t *pview = NULL; /* Production view */ + isc_mem_t *cmctx; + dns_dispatch_t *dispatch4 = NULL; + dns_dispatch_t *dispatch6 = NULL; + isc_boolean_t reused_cache = ISC_FALSE; + int i; + const char *str; + dns_order_t *order = NULL; + isc_uint32_t udpsize; + unsigned int resopts = 0; + dns_zone_t *zone = NULL; + isc_uint32_t max_clients_per_query; + const char *sep = ": view "; + const char *viewname = view->name; + const char *forview = " for view "; + isc_boolean_t rfc1918; + isc_boolean_t empty_zones_enable; + const cfg_obj_t *disablelist = NULL; + isc_stats_t *resstats = NULL; + dns_stats_t *resquerystats = NULL; + isc_boolean_t zero_no_soattl; + + REQUIRE(DNS_VIEW_VALID(view)); + + cmctx = NULL; + + if (config != NULL) + (void)cfg_map_get(config, "options", &options); + + i = 0; + if (vconfig != NULL) { + voptions = cfg_tuple_get(vconfig, "options"); + maps[i++] = voptions; + } + if (options != NULL) + maps[i++] = options; + maps[i++] = ns_g_defaults; + maps[i] = NULL; + + i = 0; + if (voptions != NULL) + cfgmaps[i++] = voptions; + if (config != NULL) + cfgmaps[i++] = config; + cfgmaps[i] = NULL; + + if (!strcmp(viewname, "_default")) { + sep = ""; + viewname = ""; + forview = ""; + } + + /* + * Set the view's port number for outgoing queries. + */ + CHECKM(ns_config_getport(config, &port), "port"); + dns_view_setdstport(view, port); + + /* + * Create additional cache for this view and zones under the view + * if explicitly enabled. + * XXX950 default to on. + */ + obj = NULL; + (void)ns_config_get(maps, "acache-enable", &obj); + if (obj != NULL && cfg_obj_asboolean(obj)) { + cmctx = NULL; + CHECK(isc_mem_create(0, 0, &cmctx)); + CHECK(dns_acache_create(&view->acache, cmctx, ns_g_taskmgr, + ns_g_timermgr)); + isc_mem_setname(cmctx, "acache", NULL); + isc_mem_detach(&cmctx); + } + if (view->acache != NULL) { + obj = NULL; + result = ns_config_get(maps, "acache-cleaning-interval", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_acache_setcleaninginterval(view->acache, + cfg_obj_asuint32(obj) * 60); + + obj = NULL; + result = ns_config_get(maps, "max-acache-size", &obj); + INSIST(result == ISC_R_SUCCESS); + if (cfg_obj_isstring(obj)) { + str = cfg_obj_asstring(obj); + INSIST(strcasecmp(str, "unlimited") == 0); + max_acache_size = ISC_UINT32_MAX; + } else { + isc_resourcevalue_t value; + + value = cfg_obj_asuint64(obj); + if (value > ISC_UINT32_MAX) { + cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, + "'max-acache-size " + "%" ISC_PRINT_QUADFORMAT + "d' is too large", + value); + result = ISC_R_RANGE; + goto cleanup; + } + max_acache_size = (isc_uint32_t)value; + } + dns_acache_setcachesize(view->acache, max_acache_size); + } + + /* + * Configure the zones. + */ + zonelist = NULL; + if (voptions != NULL) + (void)cfg_map_get(voptions, "zone", &zonelist); + else + (void)cfg_map_get(config, "zone", &zonelist); + for (element = cfg_list_first(zonelist); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *zconfig = cfg_listelt_value(element); + CHECK(configure_zone(config, zconfig, vconfig, mctx, view, + actx)); + } + +#ifdef DLZ + /* + * Create Dynamically Loadable Zone driver. + */ + dlz = NULL; + if (voptions != NULL) + (void)cfg_map_get(voptions, "dlz", &dlz); + else + (void)cfg_map_get(config, "dlz", &dlz); + + obj = NULL; + if (dlz != NULL) { + (void)cfg_map_get(cfg_tuple_get(dlz, "options"), + "database", &obj); + if (obj != NULL) { + char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj)); + if (s == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup; + } + + result = dns_dlzstrtoargv(mctx, s, &dlzargc, &dlzargv); + if (result != ISC_R_SUCCESS) { + isc_mem_free(mctx, s); + goto cleanup; + } + + obj = cfg_tuple_get(dlz, "name"); + result = dns_dlzcreate(mctx, cfg_obj_asstring(obj), + dlzargv[0], dlzargc, dlzargv, + &view->dlzdatabase); + isc_mem_free(mctx, s); + isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv)); + if (result != ISC_R_SUCCESS) + goto cleanup; + } + } +#endif + + /* + * Obtain configuration parameters that affect the decision of whether + * we can reuse/share an existing cache. + */ + /* Check-names. */ + obj = NULL; + result = ns_checknames_get(maps, "response", &obj); + INSIST(result == ISC_R_SUCCESS); + + str = cfg_obj_asstring(obj); + if (strcasecmp(str, "fail") == 0) { + resopts |= DNS_RESOLVER_CHECKNAMES | + DNS_RESOLVER_CHECKNAMESFAIL; + view->checknames = ISC_TRUE; + } else if (strcasecmp(str, "warn") == 0) { + resopts |= DNS_RESOLVER_CHECKNAMES; + view->checknames = ISC_FALSE; + } else if (strcasecmp(str, "ignore") == 0) { + view->checknames = ISC_FALSE; + } else + INSIST(0); + + obj = NULL; + result = ns_config_get(maps, "zero-no-soa-ttl-cache", &obj); + INSIST(result == ISC_R_SUCCESS); + zero_no_soattl = cfg_obj_asboolean(obj); + + obj = NULL; + result = ns_config_get(maps, "dnssec-accept-expired", &obj); + INSIST(result == ISC_R_SUCCESS); + view->acceptexpired = cfg_obj_asboolean(obj); + + obj = NULL; + result = ns_config_get(maps, "dnssec-validation", &obj); + INSIST(result == ISC_R_SUCCESS); + view->enablevalidation = cfg_obj_asboolean(obj); + + obj = NULL; + result = ns_config_get(maps, "max-cache-ttl", &obj); + INSIST(result == ISC_R_SUCCESS); + view->maxcachettl = cfg_obj_asuint32(obj); + + obj = NULL; + result = ns_config_get(maps, "max-ncache-ttl", &obj); + INSIST(result == ISC_R_SUCCESS); + view->maxncachettl = cfg_obj_asuint32(obj); + if (view->maxncachettl > 7 * 24 * 3600) + view->maxncachettl = 7 * 24 * 3600; + + /* + * Configure the view's cache. Try to reuse an existing + * cache if possible, otherwise create a new cache. + * Note that the ADB is not preserved in either case. + * When a matching view is found, the associated statistics are + * also retrieved and reused. + * + * XXX Determining when it is safe to reuse a cache is tricky. + * When the view's configuration changes, the cached data may become + * invalid because it reflects our old view of the world. We check + * some of the configuration parameters that could invalidate the cache, + * but there are other configuration options that should be checked. + * For example, if a view uses a forwarder, changes in the forwarder + * configuration may invalidate the cache. At the moment, it's the + * administrator's responsibility to ensure these configuration options + * don't invalidate reusing. + */ + result = dns_viewlist_find(&ns_g_server->viewlist, + view->name, view->rdclass, + &pview); + if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) + goto cleanup; + if (pview != NULL) { + if (cache_reusable(pview, view, zero_no_soattl)) { + INSIST(pview->cache != NULL); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(3), + "reusing existing cache"); + reused_cache = ISC_TRUE; + dns_cache_attach(pview->cache, &cache); + } else { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1), + "cache cannot be reused for view %s " + "due to configuration parameter mismatch", + view->name); + } + dns_view_getresstats(pview, &resstats); + dns_view_getresquerystats(pview, &resquerystats); + dns_view_detach(&pview); + } + if (cache == NULL) { + CHECK(isc_mem_create(0, 0, &cmctx)); + CHECK(dns_cache_create(cmctx, ns_g_taskmgr, ns_g_timermgr, + view->rdclass, "rbt", 0, NULL, &cache)); + isc_mem_setname(cmctx, "cache", NULL); + } + dns_view_setcache(view, cache); + + /* + * cache-file cannot be inherited if views are present, but this + * should be caught by the configuration checking stage. + */ + obj = NULL; + result = ns_config_get(maps, "cache-file", &obj); + if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) { + CHECK(dns_cache_setfilename(cache, cfg_obj_asstring(obj))); + if (!reused_cache) + CHECK(dns_cache_load(cache)); + } + + obj = NULL; + result = ns_config_get(maps, "cleaning-interval", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_cache_setcleaninginterval(cache, cfg_obj_asuint32(obj) * 60); + + obj = NULL; + result = ns_config_get(maps, "max-cache-size", &obj); + INSIST(result == ISC_R_SUCCESS); + if (cfg_obj_isstring(obj)) { + str = cfg_obj_asstring(obj); + INSIST(strcasecmp(str, "unlimited") == 0); + max_cache_size = ISC_UINT32_MAX; + } else { + isc_resourcevalue_t value; + value = cfg_obj_asuint64(obj); + if (value > ISC_UINT32_MAX) { + cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, + "'max-cache-size " + "%" ISC_PRINT_QUADFORMAT "d' is too large", + value); + result = ISC_R_RANGE; + goto cleanup; + } + max_cache_size = (isc_uint32_t)value; + } + dns_cache_setcachesize(cache, max_cache_size); + + dns_cache_detach(&cache); + + /* + * Resolver. + * + * XXXRTH Hardwired number of tasks. + */ + CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4, + ISC_TF(ISC_LIST_PREV(view, link) + == NULL))); + CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6, + ISC_TF(ISC_LIST_PREV(view, link) + == NULL))); + if (dispatch4 == NULL && dispatch6 == NULL) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "unable to obtain neither an IPv4 nor" + " an IPv6 dispatch"); + result = ISC_R_UNEXPECTED; + goto cleanup; + } + CHECK(dns_view_createresolver(view, ns_g_taskmgr, 31, + ns_g_socketmgr, ns_g_timermgr, + resopts, ns_g_dispatchmgr, + dispatch4, dispatch6)); + + if (resstats == NULL) { + CHECK(isc_stats_create(mctx, &resstats, + dns_resstatscounter_max)); + } + dns_view_setresstats(view, resstats); + if (resquerystats == NULL) + CHECK(dns_rdatatypestats_create(mctx, &resquerystats)); + dns_view_setresquerystats(view, resquerystats); + + /* + * Set the ADB cache size to 1/8th of the max-cache-size. + */ + max_adb_size = 0; + if (max_cache_size != 0) { + max_adb_size = max_cache_size / 8; + if (max_adb_size == 0) + max_adb_size = 1; /* Force minimum. */ + } + dns_adb_setadbsize(view->adb, max_adb_size); + + /* + * Set resolver's lame-ttl. + */ + obj = NULL; + result = ns_config_get(maps, "lame-ttl", &obj); + INSIST(result == ISC_R_SUCCESS); + lame_ttl = cfg_obj_asuint32(obj); + if (lame_ttl > 1800) + lame_ttl = 1800; + dns_resolver_setlamettl(view->resolver, lame_ttl); + + /* + * Set the resolver's EDNS UDP size. + */ + obj = NULL; + result = ns_config_get(maps, "edns-udp-size", &obj); + INSIST(result == ISC_R_SUCCESS); + udpsize = cfg_obj_asuint32(obj); + if (udpsize < 512) + udpsize = 512; + if (udpsize > 4096) + udpsize = 4096; + dns_resolver_setudpsize(view->resolver, (isc_uint16_t)udpsize); + + /* + * Set the maximum UDP response size. + */ + obj = NULL; + result = ns_config_get(maps, "max-udp-size", &obj); + INSIST(result == ISC_R_SUCCESS); + udpsize = cfg_obj_asuint32(obj); + if (udpsize < 512) + udpsize = 512; + if (udpsize > 4096) + udpsize = 4096; + view->maxudp = udpsize; + + /* + * Set supported DNSSEC algorithms. + */ + dns_resolver_reset_algorithms(view->resolver); + disabled = NULL; + (void)ns_config_get(maps, "disable-algorithms", &disabled); + if (disabled != NULL) { + for (element = cfg_list_first(disabled); + element != NULL; + element = cfg_list_next(element)) + CHECK(disable_algorithms(cfg_listelt_value(element), + view->resolver)); + } + + /* + * A global or view "forwarders" option, if present, + * creates an entry for "." in the forwarding table. + */ + forwardtype = NULL; + forwarders = NULL; + (void)ns_config_get(maps, "forward", &forwardtype); + (void)ns_config_get(maps, "forwarders", &forwarders); + if (forwarders != NULL) + CHECK(configure_forward(config, view, dns_rootname, + forwarders, forwardtype)); + + /* + * Dual Stack Servers. + */ + alternates = NULL; + (void)ns_config_get(maps, "dual-stack-servers", &alternates); + if (alternates != NULL) + CHECK(configure_alternates(config, view, alternates)); + + /* + * We have default hints for class IN if we need them. + */ + if (view->rdclass == dns_rdataclass_in && view->hints == NULL) + dns_view_sethints(view, ns_g_server->in_roothints); + + /* + * If we still have no hints, this is a non-IN view with no + * "hints zone" configured. Issue a warning, except if this + * is a root server. Root servers never need to consult + * their hints, so it's no point requiring users to configure + * them. + */ + if (view->hints == NULL) { + dns_zone_t *rootzone = NULL; + (void)dns_view_findzone(view, dns_rootname, &rootzone); + if (rootzone != NULL) { + dns_zone_detach(&rootzone); + need_hints = ISC_FALSE; + } + if (need_hints) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_WARNING, + "no root hints for view '%s'", + view->name); + } + + /* + * Configure the view's TSIG keys. + */ + ring = NULL; + CHECK(ns_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring)); + dns_view_setkeyring(view, ring); + + /* + * Configure the view's peer list. + */ + { + const cfg_obj_t *peers = NULL; + const cfg_listelt_t *element; + dns_peerlist_t *newpeers = NULL; + + (void)ns_config_get(cfgmaps, "server", &peers); + CHECK(dns_peerlist_new(mctx, &newpeers)); + for (element = cfg_list_first(peers); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *cpeer = cfg_listelt_value(element); + dns_peer_t *peer; + + CHECK(configure_peer(cpeer, mctx, &peer)); + dns_peerlist_addpeer(newpeers, peer); + dns_peer_detach(&peer); + } + dns_peerlist_detach(&view->peers); + view->peers = newpeers; /* Transfer ownership. */ + } + + /* + * Configure the views rrset-order. + */ + { + const cfg_obj_t *rrsetorder = NULL; + const cfg_listelt_t *element; + + (void)ns_config_get(maps, "rrset-order", &rrsetorder); + CHECK(dns_order_create(mctx, &order)); + for (element = cfg_list_first(rrsetorder); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *ent = cfg_listelt_value(element); + + CHECK(configure_order(order, ent)); + } + if (view->order != NULL) + dns_order_detach(&view->order); + dns_order_attach(order, &view->order); + dns_order_detach(&order); + } + /* + * Copy the aclenv object. + */ + dns_aclenv_copy(&view->aclenv, &ns_g_server->aclenv); + + /* + * Configure the "match-clients" and "match-destinations" ACL. + */ + CHECK(configure_view_acl(vconfig, config, "match-clients", actx, + ns_g_mctx, &view->matchclients)); + CHECK(configure_view_acl(vconfig, config, "match-destinations", actx, + ns_g_mctx, &view->matchdestinations)); + + /* + * Configure the "match-recursive-only" option. + */ + obj = NULL; + (void)ns_config_get(maps, "match-recursive-only", &obj); + if (obj != NULL && cfg_obj_asboolean(obj)) + view->matchrecursiveonly = ISC_TRUE; + else + view->matchrecursiveonly = ISC_FALSE; + + /* + * Configure other configurable data. + */ + obj = NULL; + result = ns_config_get(maps, "recursion", &obj); + INSIST(result == ISC_R_SUCCESS); + view->recursion = cfg_obj_asboolean(obj); + + obj = NULL; + result = ns_config_get(maps, "auth-nxdomain", &obj); + INSIST(result == ISC_R_SUCCESS); + view->auth_nxdomain = cfg_obj_asboolean(obj); + + obj = NULL; + result = ns_config_get(maps, "minimal-responses", &obj); + INSIST(result == ISC_R_SUCCESS); + view->minimalresponses = cfg_obj_asboolean(obj); + + obj = NULL; + result = ns_config_get(maps, "transfer-format", &obj); + INSIST(result == ISC_R_SUCCESS); + str = cfg_obj_asstring(obj); + if (strcasecmp(str, "many-answers") == 0) + view->transfer_format = dns_many_answers; + else if (strcasecmp(str, "one-answer") == 0) + view->transfer_format = dns_one_answer; + else + INSIST(0); + + /* + * Set sources where additional data and CNAME/DNAME + * targets for authoritative answers may be found. + */ + obj = NULL; + result = ns_config_get(maps, "additional-from-auth", &obj); + INSIST(result == ISC_R_SUCCESS); + view->additionalfromauth = cfg_obj_asboolean(obj); + if (view->recursion && ! view->additionalfromauth) { + cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, + "'additional-from-auth no' is only supported " + "with 'recursion no'"); + view->additionalfromauth = ISC_TRUE; + } + + obj = NULL; + result = ns_config_get(maps, "additional-from-cache", &obj); + INSIST(result == ISC_R_SUCCESS); + view->additionalfromcache = cfg_obj_asboolean(obj); + if (view->recursion && ! view->additionalfromcache) { + cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, + "'additional-from-cache no' is only supported " + "with 'recursion no'"); + view->additionalfromcache = ISC_TRUE; + } + + /* + * Set "allow-query-cache", "allow-query-cache-on", + * "allow-recursion", and "allow-recursion-on" acls if + * configured in named.conf. + */ + CHECK(configure_view_acl(vconfig, config, "allow-query-cache", + actx, ns_g_mctx, &view->queryacl)); + CHECK(configure_view_acl(vconfig, config, "allow-query-cache-on", + actx, ns_g_mctx, &view->queryonacl)); + if (view->queryonacl == NULL) + CHECK(configure_view_acl(NULL, ns_g_config, + "allow-query-cache-on", actx, + ns_g_mctx, &view->queryonacl)); + if (strcmp(view->name, "_bind") != 0) { + CHECK(configure_view_acl(vconfig, config, "allow-recursion", + actx, ns_g_mctx, + &view->recursionacl)); + CHECK(configure_view_acl(vconfig, config, "allow-recursion-on", + actx, ns_g_mctx, + &view->recursiononacl)); + } + + /* + * "allow-query-cache" inherits from "allow-recursion" if set, + * otherwise from "allow-query" if set. + * "allow-recursion" inherits from "allow-query-cache" if set, + * otherwise from "allow-query" if set. + */ + if (view->queryacl == NULL && view->recursionacl != NULL) + dns_acl_attach(view->recursionacl, &view->queryacl); + if (view->queryacl == NULL && view->recursion) + CHECK(configure_view_acl(vconfig, config, "allow-query", + actx, ns_g_mctx, &view->queryacl)); + if (view->recursion && + view->recursionacl == NULL && view->queryacl != NULL) + dns_acl_attach(view->queryacl, &view->recursionacl); + + /* + * Set default "allow-recursion", "allow-recursion-on" and + * "allow-query-cache" acls. + */ + if (view->recursionacl == NULL && view->recursion) + CHECK(configure_view_acl(NULL, ns_g_config, + "allow-recursion", + actx, ns_g_mctx, + &view->recursionacl)); + if (view->recursiononacl == NULL && view->recursion) + CHECK(configure_view_acl(NULL, ns_g_config, + "allow-recursion-on", + actx, ns_g_mctx, + &view->recursiononacl)); + if (view->queryacl == NULL) { + if (view->recursion) + CHECK(configure_view_acl(NULL, ns_g_config, + "allow-query-cache", actx, + ns_g_mctx, &view->queryacl)); + else { + if (view->queryacl != NULL) + dns_acl_detach(&view->queryacl); + CHECK(dns_acl_none(ns_g_mctx, &view->queryacl)); + } + } + + /* + * Configure sortlist, if set + */ + CHECK(configure_view_sortlist(vconfig, config, actx, ns_g_mctx, + &view->sortlist)); + + /* + * Configure default allow-transfer, allow-notify, allow-update + * and allow-update-forwarding ACLs, if set, so they can be + * inherited by zones. + */ + if (view->notifyacl == NULL) + CHECK(configure_view_acl(NULL, ns_g_config, + "allow-notify", actx, + ns_g_mctx, &view->notifyacl)); + if (view->transferacl == NULL) + CHECK(configure_view_acl(NULL, ns_g_config, + "allow-transfer", actx, + ns_g_mctx, &view->transferacl)); + if (view->updateacl == NULL) + CHECK(configure_view_acl(NULL, ns_g_config, + "allow-update", actx, + ns_g_mctx, &view->updateacl)); + if (view->upfwdacl == NULL) + CHECK(configure_view_acl(NULL, ns_g_config, + "allow-update-forwarding", actx, + ns_g_mctx, &view->upfwdacl)); + + obj = NULL; + result = ns_config_get(maps, "request-ixfr", &obj); + INSIST(result == ISC_R_SUCCESS); + view->requestixfr = cfg_obj_asboolean(obj); + + obj = NULL; + result = ns_config_get(maps, "provide-ixfr", &obj); + INSIST(result == ISC_R_SUCCESS); + view->provideixfr = cfg_obj_asboolean(obj); + + obj = NULL; + result = ns_config_get(maps, "request-nsid", &obj); + INSIST(result == ISC_R_SUCCESS); + view->requestnsid = cfg_obj_asboolean(obj); + + obj = NULL; + result = ns_config_get(maps, "max-clients-per-query", &obj); + INSIST(result == ISC_R_SUCCESS); + max_clients_per_query = cfg_obj_asuint32(obj); + + obj = NULL; + result = ns_config_get(maps, "clients-per-query", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_resolver_setclientsperquery(view->resolver, + cfg_obj_asuint32(obj), + max_clients_per_query); + + obj = NULL; + result = ns_config_get(maps, "dnssec-enable", &obj); + INSIST(result == ISC_R_SUCCESS); + view->enablednssec = cfg_obj_asboolean(obj); + + obj = NULL; + result = ns_config_get(maps, "dnssec-lookaside", &obj); + if (result == ISC_R_SUCCESS) { + for (element = cfg_list_first(obj); + element != NULL; + element = cfg_list_next(element)) + { + const char *str; + isc_buffer_t b; + dns_name_t *dlv; + + obj = cfg_listelt_value(element); +#if 0 + dns_fixedname_t fixed; + dns_name_t *name; + + /* + * When we support multiple dnssec-lookaside + * entries this is how to find the domain to be + * checked. XXXMPA + */ + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + str = cfg_obj_asstring(cfg_tuple_get(obj, + "domain")); + isc_buffer_init(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + CHECK(dns_name_fromtext(name, &b, dns_rootname, + ISC_TRUE, NULL)); +#endif + str = cfg_obj_asstring(cfg_tuple_get(obj, + "trust-anchor")); + isc_buffer_init(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + dlv = dns_fixedname_name(&view->dlv_fixed); + CHECK(dns_name_fromtext(dlv, &b, dns_rootname, + ISC_TRUE, NULL)); + view->dlv = dns_fixedname_name(&view->dlv_fixed); + } + } else + view->dlv = NULL; + + /* + * For now, there is only one kind of trusted keys, the + * "security roots". + */ + CHECK(configure_view_dnsseckeys(vconfig, config, mctx, + &view->secroots)); + dns_resolver_resetmustbesecure(view->resolver); + obj = NULL; + result = ns_config_get(maps, "dnssec-must-be-secure", &obj); + if (result == ISC_R_SUCCESS) + CHECK(mustbesecure(obj, view->resolver)); + + obj = NULL; + result = ns_config_get(maps, "preferred-glue", &obj); + if (result == ISC_R_SUCCESS) { + str = cfg_obj_asstring(obj); + if (strcasecmp(str, "a") == 0) + view->preferred_glue = dns_rdatatype_a; + else if (strcasecmp(str, "aaaa") == 0) + view->preferred_glue = dns_rdatatype_aaaa; + else + view->preferred_glue = 0; + } else + view->preferred_glue = 0; + + obj = NULL; + result = ns_config_get(maps, "root-delegation-only", &obj); + if (result == ISC_R_SUCCESS) { + dns_view_setrootdelonly(view, ISC_TRUE); + if (!cfg_obj_isvoid(obj)) { + dns_fixedname_t fixed; + dns_name_t *name; + isc_buffer_t b; + const char *str; + const cfg_obj_t *exclude; + + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + for (element = cfg_list_first(obj); + element != NULL; + element = cfg_list_next(element)) { + exclude = cfg_listelt_value(element); + str = cfg_obj_asstring(exclude); + isc_buffer_init(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + CHECK(dns_name_fromtext(name, &b, dns_rootname, + ISC_FALSE, NULL)); + CHECK(dns_view_excludedelegationonly(view, + name)); + } + } + } else + dns_view_setrootdelonly(view, ISC_FALSE); + + /* + * Setup automatic empty zones. If recursion is off then + * they are disabled by default. + */ + obj = NULL; + (void)ns_config_get(maps, "empty-zones-enable", &obj); + (void)ns_config_get(maps, "disable-empty-zone", &disablelist); + if (obj == NULL && disablelist == NULL && + view->rdclass == dns_rdataclass_in) { + rfc1918 = ISC_FALSE; + empty_zones_enable = view->recursion; + } else if (view->rdclass == dns_rdataclass_in) { + rfc1918 = ISC_TRUE; + if (obj != NULL) + empty_zones_enable = cfg_obj_asboolean(obj); + else + empty_zones_enable = view->recursion; + } else { + rfc1918 = ISC_FALSE; + empty_zones_enable = ISC_FALSE; + } + if (empty_zones_enable) { + const char *empty; + int empty_zone = 0; + dns_fixedname_t fixed; + dns_name_t *name; + isc_buffer_t buffer; + const char *str; + char server[DNS_NAME_FORMATSIZE + 1]; + char contact[DNS_NAME_FORMATSIZE + 1]; + isc_boolean_t logit; + const char *empty_dbtype[4] = + { "_builtin", "empty", NULL, NULL }; + int empty_dbtypec = 4; + isc_boolean_t zonestats_on; + + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + + obj = NULL; + result = ns_config_get(maps, "empty-server", &obj); + if (result == ISC_R_SUCCESS) { + str = cfg_obj_asstring(obj); + isc_buffer_init(&buffer, str, strlen(str)); + isc_buffer_add(&buffer, strlen(str)); + CHECK(dns_name_fromtext(name, &buffer, dns_rootname, + ISC_FALSE, NULL)); + isc_buffer_init(&buffer, server, sizeof(server) - 1); + CHECK(dns_name_totext(name, ISC_FALSE, &buffer)); + server[isc_buffer_usedlength(&buffer)] = 0; + empty_dbtype[2] = server; + } else + empty_dbtype[2] = "@"; + + obj = NULL; + result = ns_config_get(maps, "empty-contact", &obj); + if (result == ISC_R_SUCCESS) { + str = cfg_obj_asstring(obj); + isc_buffer_init(&buffer, str, strlen(str)); + isc_buffer_add(&buffer, strlen(str)); + CHECK(dns_name_fromtext(name, &buffer, dns_rootname, + ISC_FALSE, NULL)); + isc_buffer_init(&buffer, contact, sizeof(contact) - 1); + CHECK(dns_name_totext(name, ISC_FALSE, &buffer)); + contact[isc_buffer_usedlength(&buffer)] = 0; + empty_dbtype[3] = contact; + } else + empty_dbtype[3] = "."; + + obj = NULL; + result = ns_config_get(maps, "zone-statistics", &obj); + INSIST(result == ISC_R_SUCCESS); + zonestats_on = cfg_obj_asboolean(obj); + + logit = ISC_TRUE; + for (empty = empty_zones[empty_zone].zone; + empty != NULL; + empty = empty_zones[++empty_zone].zone) + { + dns_forwarders_t *forwarders = NULL; + dns_view_t *pview = NULL; + + isc_buffer_init(&buffer, empty, strlen(empty)); + isc_buffer_add(&buffer, strlen(empty)); + /* + * Look for zone on drop list. + */ + CHECK(dns_name_fromtext(name, &buffer, dns_rootname, + ISC_FALSE, NULL)); + if (disablelist != NULL && + on_disable_list(disablelist, name)) + continue; + + /* + * This zone already exists. + */ + (void)dns_view_findzone(view, name, &zone); + if (zone != NULL) { + CHECK(setquerystats(zone, mctx, zonestats_on)); + dns_zone_detach(&zone); + continue; + } + + /* + * If we would forward this name don't add a + * empty zone for it. + */ + result = dns_fwdtable_find(view->fwdtable, name, + &forwarders); + if (result == ISC_R_SUCCESS && + forwarders->fwdpolicy == dns_fwdpolicy_only) + continue; + + if (!rfc1918 && empty_zones[empty_zone].rfc1918) { + if (logit) { + isc_log_write(ns_g_lctx, + NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, + ISC_LOG_WARNING, + "Warning%s%s: " + "'empty-zones-enable/" + "disable-empty-zone' " + "not set: disabling " + "RFC 1918 empty zones", + sep, viewname); + logit = ISC_FALSE; + } + continue; + } + + /* + * See if we can re-use a existing zone. + */ + result = dns_viewlist_find(&ns_g_server->viewlist, + view->name, view->rdclass, + &pview); + if (result != ISC_R_NOTFOUND && + result != ISC_R_SUCCESS) + goto cleanup; + + if (pview != NULL) { + (void)dns_view_findzone(pview, name, &zone); + dns_view_detach(&pview); + if (zone != NULL) + check_dbtype(&zone, empty_dbtypec, + empty_dbtype, mctx); + if (zone != NULL) { + dns_zone_setview(zone, view); + CHECK(dns_view_addzone(view, zone)); + CHECK(setquerystats(zone, mctx, + zonestats_on)); + dns_zone_detach(&zone); + continue; + } + } + + CHECK(dns_zone_create(&zone, mctx)); + CHECK(dns_zone_setorigin(zone, name)); + dns_zone_setview(zone, view); + CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); + dns_zone_setclass(zone, view->rdclass); + dns_zone_settype(zone, dns_zone_master); + dns_zone_setstats(zone, ns_g_server->zonestats); + CHECK(dns_zone_setdbtype(zone, empty_dbtypec, + empty_dbtype)); + if (view->queryacl != NULL) + dns_zone_setqueryacl(zone, view->queryacl); + if (view->queryonacl != NULL) + dns_zone_setqueryonacl(zone, view->queryonacl); + dns_zone_setdialup(zone, dns_dialuptype_no); + dns_zone_setnotifytype(zone, dns_notifytype_no); + dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, + ISC_TRUE); + CHECK(setquerystats(zone, mctx, zonestats_on)); + CHECK(dns_view_addzone(view, zone)); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "automatic empty zone%s%s: %s", + sep, viewname, empty); + dns_zone_detach(&zone); + } + } + + result = ISC_R_SUCCESS; + + cleanup: + if (zone != NULL) + dns_zone_detach(&zone); + if (dispatch4 != NULL) + dns_dispatch_detach(&dispatch4); + if (dispatch6 != NULL) + dns_dispatch_detach(&dispatch6); + if (resstats != NULL) + isc_stats_detach(&resstats); + if (resquerystats != NULL) + dns_stats_detach(&resquerystats); + if (order != NULL) + dns_order_detach(&order); + if (cmctx != NULL) + isc_mem_detach(&cmctx); + + if (cache != NULL) + dns_cache_detach(&cache); + + return (result); +} + +static isc_result_t +configure_hints(dns_view_t *view, const char *filename) { + isc_result_t result; + dns_db_t *db; + + db = NULL; + result = dns_rootns_create(view->mctx, view->rdclass, filename, &db); + if (result == ISC_R_SUCCESS) { + dns_view_sethints(view, db); + dns_db_detach(&db); + } + + return (result); +} + +static isc_result_t +configure_alternates(const cfg_obj_t *config, dns_view_t *view, + const cfg_obj_t *alternates) +{ + const cfg_obj_t *portobj; + const cfg_obj_t *addresses; + const cfg_listelt_t *element; + isc_result_t result = ISC_R_SUCCESS; + in_port_t port; + + /* + * Determine which port to send requests to. + */ + if (ns_g_lwresdonly && ns_g_port != 0) + port = ns_g_port; + else + CHECKM(ns_config_getport(config, &port), "port"); + + if (alternates != NULL) { + portobj = cfg_tuple_get(alternates, "port"); + if (cfg_obj_isuint32(portobj)) { + isc_uint32_t val = cfg_obj_asuint32(portobj); + if (val > ISC_UINT16_MAX) { + cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, + "port '%u' out of range", val); + return (ISC_R_RANGE); + } + port = (in_port_t) val; + } + } + + addresses = NULL; + if (alternates != NULL) + addresses = cfg_tuple_get(alternates, "addresses"); + + for (element = cfg_list_first(addresses); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *alternate = cfg_listelt_value(element); + isc_sockaddr_t sa; + + if (!cfg_obj_issockaddr(alternate)) { + dns_fixedname_t fixed; + dns_name_t *name; + const char *str = cfg_obj_asstring(cfg_tuple_get( + alternate, "name")); + isc_buffer_t buffer; + in_port_t myport = port; + + isc_buffer_init(&buffer, str, strlen(str)); + isc_buffer_add(&buffer, strlen(str)); + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + CHECK(dns_name_fromtext(name, &buffer, dns_rootname, + ISC_FALSE, NULL)); + + portobj = cfg_tuple_get(alternate, "port"); + if (cfg_obj_isuint32(portobj)) { + isc_uint32_t val = cfg_obj_asuint32(portobj); + if (val > ISC_UINT16_MAX) { + cfg_obj_log(portobj, ns_g_lctx, + ISC_LOG_ERROR, + "port '%u' out of range", + val); + return (ISC_R_RANGE); + } + myport = (in_port_t) val; + } + CHECK(dns_resolver_addalternate(view->resolver, NULL, + name, myport)); + continue; + } + + sa = *cfg_obj_assockaddr(alternate); + if (isc_sockaddr_getport(&sa) == 0) + isc_sockaddr_setport(&sa, port); + CHECK(dns_resolver_addalternate(view->resolver, &sa, + NULL, 0)); + } + + cleanup: + return (result); +} + +static isc_result_t +configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, + const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype) +{ + const cfg_obj_t *portobj; + const cfg_obj_t *faddresses; + const cfg_listelt_t *element; + dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none; + isc_sockaddrlist_t addresses; + isc_sockaddr_t *sa; + isc_result_t result; + in_port_t port; + + ISC_LIST_INIT(addresses); + + /* + * Determine which port to send forwarded requests to. + */ + if (ns_g_lwresdonly && ns_g_port != 0) + port = ns_g_port; + else + CHECKM(ns_config_getport(config, &port), "port"); + + if (forwarders != NULL) { + portobj = cfg_tuple_get(forwarders, "port"); + if (cfg_obj_isuint32(portobj)) { + isc_uint32_t val = cfg_obj_asuint32(portobj); + if (val > ISC_UINT16_MAX) { + cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, + "port '%u' out of range", val); + return (ISC_R_RANGE); + } + port = (in_port_t) val; + } + } + + faddresses = NULL; + if (forwarders != NULL) + faddresses = cfg_tuple_get(forwarders, "addresses"); + + for (element = cfg_list_first(faddresses); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *forwarder = cfg_listelt_value(element); + sa = isc_mem_get(view->mctx, sizeof(isc_sockaddr_t)); + if (sa == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup; + } + *sa = *cfg_obj_assockaddr(forwarder); + if (isc_sockaddr_getport(sa) == 0) + isc_sockaddr_setport(sa, port); + ISC_LINK_INIT(sa, link); + ISC_LIST_APPEND(addresses, sa, link); + } + + if (ISC_LIST_EMPTY(addresses)) { + if (forwardtype != NULL) + cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING, + "no forwarders seen; disabling " + "forwarding"); + fwdpolicy = dns_fwdpolicy_none; + } else { + if (forwardtype == NULL) + fwdpolicy = dns_fwdpolicy_first; + else { + const char *forwardstr = cfg_obj_asstring(forwardtype); + if (strcasecmp(forwardstr, "first") == 0) + fwdpolicy = dns_fwdpolicy_first; + else if (strcasecmp(forwardstr, "only") == 0) + fwdpolicy = dns_fwdpolicy_only; + else + INSIST(0); + } + } + + result = dns_fwdtable_add(view->fwdtable, origin, &addresses, + fwdpolicy); + if (result != ISC_R_SUCCESS) { + char namebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(origin, namebuf, sizeof(namebuf)); + cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING, + "could not set up forwarding for domain '%s': %s", + namebuf, isc_result_totext(result)); + goto cleanup; + } + + result = ISC_R_SUCCESS; + + cleanup: + + while (!ISC_LIST_EMPTY(addresses)) { + sa = ISC_LIST_HEAD(addresses); + ISC_LIST_UNLINK(addresses, sa, link); + isc_mem_put(view->mctx, sa, sizeof(isc_sockaddr_t)); + } + + return (result); +} + +/* + * Create a new view and add it to the list. + * + * If 'vconfig' is NULL, create the default view. + * + * The view created is attached to '*viewp'. + */ +static isc_result_t +create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist, + dns_view_t **viewp) +{ + isc_result_t result; + const char *viewname; + dns_rdataclass_t viewclass; + dns_view_t *view = NULL; + + if (vconfig != NULL) { + const cfg_obj_t *classobj = NULL; + + viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name")); + classobj = cfg_tuple_get(vconfig, "class"); + result = ns_config_getclass(classobj, dns_rdataclass_in, + &viewclass); + } else { + viewname = "_default"; + viewclass = dns_rdataclass_in; + } + result = dns_viewlist_find(viewlist, viewname, viewclass, &view); + if (result == ISC_R_SUCCESS) + return (ISC_R_EXISTS); + if (result != ISC_R_NOTFOUND) + return (result); + INSIST(view == NULL); + + result = dns_view_create(ns_g_mctx, viewclass, viewname, &view); + if (result != ISC_R_SUCCESS) + return (result); + + ISC_LIST_APPEND(*viewlist, view, link); + dns_view_attach(view, viewp); + return (ISC_R_SUCCESS); +} + +/* + * Configure or reconfigure a zone. + */ +static isc_result_t +configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, + const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, + cfg_aclconfctx_t *aclconf) +{ + dns_view_t *pview = NULL; /* Production view */ + dns_zone_t *zone = NULL; /* New or reused zone */ + dns_zone_t *dupzone = NULL; + const cfg_obj_t *options = NULL; + const cfg_obj_t *zoptions = NULL; + const cfg_obj_t *typeobj = NULL; + const cfg_obj_t *forwarders = NULL; + const cfg_obj_t *forwardtype = NULL; + const cfg_obj_t *only = NULL; + isc_result_t result; + isc_result_t tresult; + isc_buffer_t buffer; + dns_fixedname_t fixorigin; + dns_name_t *origin; + const char *zname; + dns_rdataclass_t zclass; + const char *ztypestr; + + options = NULL; + (void)cfg_map_get(config, "options", &options); + + zoptions = cfg_tuple_get(zconfig, "options"); + + /* + * Get the zone origin as a dns_name_t. + */ + zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); + isc_buffer_init(&buffer, zname, strlen(zname)); + isc_buffer_add(&buffer, strlen(zname)); + dns_fixedname_init(&fixorigin); + CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin), + &buffer, dns_rootname, ISC_FALSE, NULL)); + origin = dns_fixedname_name(&fixorigin); + + CHECK(ns_config_getclass(cfg_tuple_get(zconfig, "class"), + view->rdclass, &zclass)); + if (zclass != view->rdclass) { + const char *vname = NULL; + if (vconfig != NULL) + vname = cfg_obj_asstring(cfg_tuple_get(vconfig, + "name")); + else + vname = ""; + + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "zone '%s': wrong class for view '%s'", + zname, vname); + result = ISC_R_FAILURE; + goto cleanup; + } + + (void)cfg_map_get(zoptions, "type", &typeobj); + if (typeobj == NULL) { + cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, + "zone '%s' 'type' not specified", zname); + return (ISC_R_FAILURE); + } + ztypestr = cfg_obj_asstring(typeobj); + + /* + * "hints zones" aren't zones. If we've got one, + * configure it and return. + */ + if (strcasecmp(ztypestr, "hint") == 0) { + const cfg_obj_t *fileobj = NULL; + if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "zone '%s': 'file' not specified", + zname); + result = ISC_R_FAILURE; + goto cleanup; + } + if (dns_name_equal(origin, dns_rootname)) { + const char *hintsfile = cfg_obj_asstring(fileobj); + + result = configure_hints(view, hintsfile); + if (result != ISC_R_SUCCESS) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, + ISC_LOG_ERROR, + "could not configure root hints " + "from '%s': %s", hintsfile, + isc_result_totext(result)); + goto cleanup; + } + /* + * Hint zones may also refer to delegation only points. + */ + only = NULL; + tresult = cfg_map_get(zoptions, "delegation-only", + &only); + if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only)) + CHECK(dns_view_adddelegationonly(view, origin)); + } else { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_WARNING, + "ignoring non-root hint zone '%s'", + zname); + result = ISC_R_SUCCESS; + } + /* Skip ordinary zone processing. */ + goto cleanup; + } + + /* + * "forward zones" aren't zones either. Translate this syntax into + * the appropriate selective forwarding configuration and return. + */ + if (strcasecmp(ztypestr, "forward") == 0) { + forwardtype = NULL; + forwarders = NULL; + + (void)cfg_map_get(zoptions, "forward", &forwardtype); + (void)cfg_map_get(zoptions, "forwarders", &forwarders); + result = configure_forward(config, view, origin, forwarders, + forwardtype); + goto cleanup; + } + + /* + * "delegation-only zones" aren't zones either. + */ + if (strcasecmp(ztypestr, "delegation-only") == 0) { + result = dns_view_adddelegationonly(view, origin); + goto cleanup; + } + + /* + * Check for duplicates in the new zone table. + */ + result = dns_view_findzone(view, origin, &dupzone); + if (result == ISC_R_SUCCESS) { + /* + * We already have this zone! + */ + cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, + "zone '%s' already exists", zname); + dns_zone_detach(&dupzone); + result = ISC_R_EXISTS; + goto cleanup; + } + INSIST(dupzone == NULL); + + /* + * See if we can reuse an existing zone. This is + * only possible if all of these are true: + * - The zone's view exists + * - A zone with the right name exists in the view + * - The zone is compatible with the config + * options (e.g., an existing master zone cannot + * be reused if the options specify a slave zone) + */ + result = dns_viewlist_find(&ns_g_server->viewlist, + view->name, view->rdclass, + &pview); + if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) + goto cleanup; + if (pview != NULL) + result = dns_view_findzone(pview, origin, &zone); + if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) + goto cleanup; + if (zone != NULL && !ns_zone_reusable(zone, zconfig)) + dns_zone_detach(&zone); + + if (zone != NULL) { + /* + * We found a reusable zone. Make it use the + * new view. + */ + dns_zone_setview(zone, view); + if (view->acache != NULL) + dns_zone_setacache(zone, view->acache); + } else { + /* + * We cannot reuse an existing zone, we have + * to create a new one. + */ + CHECK(dns_zone_create(&zone, mctx)); + CHECK(dns_zone_setorigin(zone, origin)); + dns_zone_setview(zone, view); + if (view->acache != NULL) + dns_zone_setacache(zone, view->acache); + CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); + dns_zone_setstats(zone, ns_g_server->zonestats); + } + + /* + * If the zone contains a 'forwarders' statement, configure + * selective forwarding. + */ + forwarders = NULL; + if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS) + { + forwardtype = NULL; + (void)cfg_map_get(zoptions, "forward", &forwardtype); + CHECK(configure_forward(config, view, origin, forwarders, + forwardtype)); + } + + /* + * Stub and forward zones may also refer to delegation only points. + */ + only = NULL; + if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS) + { + if (cfg_obj_asboolean(only)) + CHECK(dns_view_adddelegationonly(view, origin)); + } + + /* + * Configure the zone. + */ + CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf, zone)); + + /* + * Add the zone to its view in the new view list. + */ + CHECK(dns_view_addzone(view, zone)); + + cleanup: + if (zone != NULL) + dns_zone_detach(&zone); + if (pview != NULL) + dns_view_detach(&pview); + + return (result); +} + +/* + * Configure a single server quota. + */ +static void +configure_server_quota(const cfg_obj_t **maps, const char *name, + isc_quota_t *quota) +{ + const cfg_obj_t *obj = NULL; + isc_result_t result; + + result = ns_config_get(maps, name, &obj); + INSIST(result == ISC_R_SUCCESS); + isc_quota_max(quota, cfg_obj_asuint32(obj)); +} + +/* + * This function is called as soon as the 'directory' statement has been + * parsed. This can be extended to support other options if necessary. + */ +static isc_result_t +directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) { + isc_result_t result; + const char *directory; + + REQUIRE(strcasecmp("directory", clausename) == 0); + + UNUSED(arg); + UNUSED(clausename); + + /* + * Change directory. + */ + directory = cfg_obj_asstring(obj); + + if (! isc_file_ischdiridempotent(directory)) + cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, + "option 'directory' contains relative path '%s'", + directory); + + result = isc_dir_chdir(directory); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, + "change directory to '%s' failed: %s", + directory, isc_result_totext(result)); + return (result); + } + + return (ISC_R_SUCCESS); +} + +static void +scan_interfaces(ns_server_t *server, isc_boolean_t verbose) { + isc_boolean_t match_mapped = server->aclenv.match_mapped; + + ns_interfacemgr_scan(server->interfacemgr, verbose); + /* + * Update the "localhost" and "localnets" ACLs to match the + * current set of network interfaces. + */ + dns_aclenv_copy(&server->aclenv, + ns_interfacemgr_getaclenv(server->interfacemgr)); + + server->aclenv.match_mapped = match_mapped; +} + +static isc_result_t +add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr, + isc_boolean_t wcardport_ok) +{ + ns_listenelt_t *lelt = NULL; + dns_acl_t *src_acl = NULL; + isc_result_t result; + isc_sockaddr_t any_sa6; + isc_netaddr_t netaddr; + + REQUIRE(isc_sockaddr_pf(addr) == AF_INET6); + + isc_sockaddr_any6(&any_sa6); + if (!isc_sockaddr_equal(&any_sa6, addr) && + (wcardport_ok || isc_sockaddr_getport(addr) != 0)) { + isc_netaddr_fromin6(&netaddr, &addr->type.sin6.sin6_addr); + + result = dns_acl_create(mctx, 0, &src_acl); + if (result != ISC_R_SUCCESS) + return (result); + + result = dns_iptable_addprefix(src_acl->iptable, + &netaddr, 128, ISC_TRUE); + if (result != ISC_R_SUCCESS) + goto clean; + + result = ns_listenelt_create(mctx, isc_sockaddr_getport(addr), + src_acl, &lelt); + if (result != ISC_R_SUCCESS) + goto clean; + ISC_LIST_APPEND(list->elts, lelt, link); + } + + return (ISC_R_SUCCESS); + + clean: + INSIST(lelt == NULL); + dns_acl_detach(&src_acl); + + return (result); +} + +/* + * Make a list of xxx-source addresses and call ns_interfacemgr_adjust() + * to update the listening interfaces accordingly. + * We currently only consider IPv6, because this only affects IPv6 wildcard + * sockets. + */ +static void +adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) { + isc_result_t result; + ns_listenlist_t *list = NULL; + dns_view_t *view; + dns_zone_t *zone, *next; + isc_sockaddr_t addr, *addrp; + + result = ns_listenlist_create(mctx, &list); + if (result != ISC_R_SUCCESS) + return; + + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) { + dns_dispatch_t *dispatch6; + + dispatch6 = dns_resolver_dispatchv6(view->resolver); + if (dispatch6 == NULL) + continue; + result = dns_dispatch_getlocaladdress(dispatch6, &addr); + if (result != ISC_R_SUCCESS) + goto fail; + + /* + * We always add non-wildcard address regardless of whether + * the port is 'any' (the fourth arg is TRUE): if the port is + * specific, we need to add it since it may conflict with a + * listening interface; if it's zero, we'll dynamically open + * query ports, and some of them may override an existing + * wildcard IPv6 port. + */ + result = add_listenelt(mctx, list, &addr, ISC_TRUE); + if (result != ISC_R_SUCCESS) + goto fail; + } + + zone = NULL; + for (result = dns_zone_first(server->zonemgr, &zone); + result == ISC_R_SUCCESS; + next = NULL, result = dns_zone_next(zone, &next), zone = next) { + dns_view_t *zoneview; + + /* + * At this point the zone list may contain a stale zone + * just removed from the configuration. To see the validity, + * check if the corresponding view is in our current view list. + * There may also be old zones that are still in the process + * of shutting down and have detached from their old view + * (zoneview == NULL). + */ + zoneview = dns_zone_getview(zone); + if (zoneview == NULL) + continue; + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL && view != zoneview; + view = ISC_LIST_NEXT(view, link)) + ; + if (view == NULL) + continue; + + addrp = dns_zone_getnotifysrc6(zone); + result = add_listenelt(mctx, list, addrp, ISC_FALSE); + if (result != ISC_R_SUCCESS) + goto fail; + + addrp = dns_zone_getxfrsource6(zone); + result = add_listenelt(mctx, list, addrp, ISC_FALSE); + if (result != ISC_R_SUCCESS) + goto fail; + } + + ns_interfacemgr_adjust(server->interfacemgr, list, ISC_TRUE); + + clean: + ns_listenlist_detach(&list); + return; + + fail: + /* + * Even when we failed the procedure, most of other interfaces + * should work correctly. We therefore just warn it. + */ + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_WARNING, + "could not adjust the listen-on list; " + "some interfaces may not work"); + goto clean; +} + +/* + * This event callback is invoked to do periodic network + * interface scanning. + */ +static void +interface_timer_tick(isc_task_t *task, isc_event_t *event) { + isc_result_t result; + ns_server_t *server = (ns_server_t *) event->ev_arg; + INSIST(task == server->task); + UNUSED(task); + isc_event_free(&event); + /* + * XXX should scan interfaces unlocked and get exclusive access + * only to replace ACLs. + */ + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + scan_interfaces(server, ISC_FALSE); + isc_task_endexclusive(server->task); +} + +static void +heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) { + ns_server_t *server = (ns_server_t *) event->ev_arg; + dns_view_t *view; + + UNUSED(task); + isc_event_free(&event); + view = ISC_LIST_HEAD(server->viewlist); + while (view != NULL) { + dns_view_dialup(view); + view = ISC_LIST_NEXT(view, link); + } +} + +static void +pps_timer_tick(isc_task_t *task, isc_event_t *event) { + static unsigned int oldrequests = 0; + unsigned int requests = ns_client_requests; + + UNUSED(task); + isc_event_free(&event); + + /* + * Don't worry about wrapping as the overflow result will be right. + */ + dns_pps = (requests - oldrequests) / 1200; + oldrequests = requests; +} + +/* + * Replace the current value of '*field', a dynamically allocated + * string or NULL, with a dynamically allocated copy of the + * null-terminated string pointed to by 'value', or NULL. + */ +static isc_result_t +setstring(ns_server_t *server, char **field, const char *value) { + char *copy; + + if (value != NULL) { + copy = isc_mem_strdup(server->mctx, value); + if (copy == NULL) + return (ISC_R_NOMEMORY); + } else { + copy = NULL; + } + + if (*field != NULL) + isc_mem_free(server->mctx, *field); + + *field = copy; + return (ISC_R_SUCCESS); +} + +/* + * Replace the current value of '*field', a dynamically allocated + * string or NULL, with another dynamically allocated string + * or NULL if whether 'obj' is a string or void value, respectively. + */ +static isc_result_t +setoptstring(ns_server_t *server, char **field, const cfg_obj_t *obj) { + if (cfg_obj_isvoid(obj)) + return (setstring(server, field, NULL)); + else + return (setstring(server, field, cfg_obj_asstring(obj))); +} + +static void +set_limit(const cfg_obj_t **maps, const char *configname, + const char *description, isc_resource_t resourceid, + isc_resourcevalue_t defaultvalue) +{ + const cfg_obj_t *obj = NULL; + const char *resource; + isc_resourcevalue_t value; + isc_result_t result; + + if (ns_config_get(maps, configname, &obj) != ISC_R_SUCCESS) + return; + + if (cfg_obj_isstring(obj)) { + resource = cfg_obj_asstring(obj); + if (strcasecmp(resource, "unlimited") == 0) + value = ISC_RESOURCE_UNLIMITED; + else { + INSIST(strcasecmp(resource, "default") == 0); + value = defaultvalue; + } + } else + value = cfg_obj_asuint64(obj); + + result = isc_resource_setlimit(resourceid, value); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, + result == ISC_R_SUCCESS ? + ISC_LOG_DEBUG(3) : ISC_LOG_WARNING, + "set maximum %s to %" ISC_PRINT_QUADFORMAT "d: %s", + description, value, isc_result_totext(result)); +} + +#define SETLIMIT(cfgvar, resource, description) \ + set_limit(maps, cfgvar, description, isc_resource_ ## resource, \ + ns_g_init ## resource) + +static void +set_limits(const cfg_obj_t **maps) { + SETLIMIT("stacksize", stacksize, "stack size"); + SETLIMIT("datasize", datasize, "data size"); + SETLIMIT("coresize", coresize, "core size"); + SETLIMIT("files", openfiles, "open files"); +} + +static void +portset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports, + isc_boolean_t positive) +{ + const cfg_listelt_t *element; + + for (element = cfg_list_first(ports); + element != NULL; + element = cfg_list_next(element)) { + const cfg_obj_t *obj = cfg_listelt_value(element); + + if (cfg_obj_isuint32(obj)) { + in_port_t port = (in_port_t)cfg_obj_asuint32(obj); + + if (positive) + isc_portset_add(portset, port); + else + isc_portset_remove(portset, port); + } else { + const cfg_obj_t *obj_loport, *obj_hiport; + in_port_t loport, hiport; + + obj_loport = cfg_tuple_get(obj, "loport"); + loport = (in_port_t)cfg_obj_asuint32(obj_loport); + obj_hiport = cfg_tuple_get(obj, "hiport"); + hiport = (in_port_t)cfg_obj_asuint32(obj_hiport); + + if (positive) + isc_portset_addrange(portset, loport, hiport); + else { + isc_portset_removerange(portset, loport, + hiport); + } + } + } +} + +static isc_result_t +removed(dns_zone_t *zone, void *uap) { + const char *type; + + if (dns_zone_getview(zone) != uap) + return (ISC_R_SUCCESS); + + switch (dns_zone_gettype(zone)) { + case dns_zone_master: + type = "master"; + break; + case dns_zone_slave: + type = "slave"; + break; + case dns_zone_stub: + type = "stub"; + break; + default: + type = "other"; + break; + } + dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed", type); + return (ISC_R_SUCCESS); +} + +static isc_result_t +load_configuration(const char *filename, ns_server_t *server, + isc_boolean_t first_time) +{ + cfg_aclconfctx_t aclconfctx; + cfg_obj_t *config; + cfg_parser_t *parser = NULL; + const cfg_listelt_t *element; + const cfg_obj_t *builtin_views; + const cfg_obj_t *maps[3]; + const cfg_obj_t *obj; + const cfg_obj_t *options; + const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports; + const cfg_obj_t *views; + dns_view_t *view = NULL; + dns_view_t *view_next; + dns_viewlist_t tmpviewlist; + dns_viewlist_t viewlist; + in_port_t listen_port, udpport_low, udpport_high; + int i; + isc_interval_t interval; + isc_portset_t *v4portset = NULL; + isc_portset_t *v6portset = NULL; + isc_resourcevalue_t nfiles; + isc_result_t result; + isc_uint32_t heartbeat_interval; + isc_uint32_t interface_interval; + isc_uint32_t reserved; + isc_uint32_t udpsize; + unsigned int maxsocks; + + cfg_aclconfctx_init(&aclconfctx); + ISC_LIST_INIT(viewlist); + + /* Ensure exclusive access to configuration data. */ + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + /* + * Parse the global default pseudo-config file. + */ + if (first_time) { + CHECK(ns_config_parsedefaults(ns_g_parser, &ns_g_config)); + RUNTIME_CHECK(cfg_map_get(ns_g_config, "options", + &ns_g_defaults) == + ISC_R_SUCCESS); + } + + /* + * Parse the configuration file using the new config code. + */ + result = ISC_R_FAILURE; + config = NULL; + + /* + * Unless this is lwresd with the -C option, parse the config file. + */ + if (!(ns_g_lwresdonly && lwresd_g_useresolvconf)) { + isc_log_write(ns_g_lctx, + NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, + ISC_LOG_INFO, "loading configuration from '%s'", + filename); + CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &parser)); + cfg_parser_setcallback(parser, directory_callback, NULL); + result = cfg_parse_file(parser, filename, &cfg_type_namedconf, + &config); + } + + /* + * If this is lwresd with the -C option, or lwresd with no -C or -c + * option where the above parsing failed, parse resolv.conf. + */ + if (ns_g_lwresdonly && + (lwresd_g_useresolvconf || + (!ns_g_conffileset && result == ISC_R_FILENOTFOUND))) + { + isc_log_write(ns_g_lctx, + NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, + ISC_LOG_INFO, "loading configuration from '%s'", + lwresd_g_resolvconffile); + if (parser != NULL) + cfg_parser_destroy(&parser); + CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &parser)); + result = ns_lwresd_parseeresolvconf(ns_g_mctx, parser, + &config); + } + CHECK(result); + + /* + * Check the validity of the configuration. + */ + CHECK(bind9_check_namedconf(config, ns_g_lctx, ns_g_mctx)); + + /* + * Fill in the maps array, used for resolving defaults. + */ + i = 0; + options = NULL; + result = cfg_map_get(config, "options", &options); + if (result == ISC_R_SUCCESS) + maps[i++] = options; + maps[i++] = ns_g_defaults; + maps[i++] = NULL; + + /* + * Set process limits, which (usually) needs to be done as root. + */ + set_limits(maps); + + /* + * Check if max number of open sockets that the system allows is + * sufficiently large. Failing this condition is not necessarily fatal, + * but may cause subsequent runtime failures for a busy recursive + * server. + */ + result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &maxsocks); + if (result != ISC_R_SUCCESS) + maxsocks = 0; + result = isc_resource_getcurlimit(isc_resource_openfiles, &nfiles); + if (result == ISC_R_SUCCESS && (isc_resourcevalue_t)maxsocks > nfiles) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_WARNING, + "max open files (%" ISC_PRINT_QUADFORMAT "u)" + " is smaller than max sockets (%u)", + nfiles, maxsocks); + } + + /* + * Set the number of socket reserved for TCP, stdio etc. + */ + obj = NULL; + result = ns_config_get(maps, "reserved-sockets", &obj); + INSIST(result == ISC_R_SUCCESS); + reserved = cfg_obj_asuint32(obj); + if (maxsocks != 0) { + if (maxsocks < 128U) /* Prevent underflow. */ + reserved = 0; + else if (reserved > maxsocks - 128U) /* Minimum UDP space. */ + reserved = maxsocks - 128; + } + /* Minimum TCP/stdio space. */ + if (reserved < 128U) + reserved = 128; + if (reserved + 128U > maxsocks && maxsocks != 0) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_WARNING, + "less than 128 UDP sockets available after " + "applying 'reserved-sockets' and 'maxsockets'"); + } + isc__socketmgr_setreserved(ns_g_socketmgr, reserved); + + /* + * Configure various server options. + */ + configure_server_quota(maps, "transfers-out", &server->xfroutquota); + configure_server_quota(maps, "tcp-clients", &server->tcpquota); + configure_server_quota(maps, "recursive-clients", + &server->recursionquota); + if (server->recursionquota.max > 1000) + isc_quota_soft(&server->recursionquota, + server->recursionquota.max - 100); + else + isc_quota_soft(&server->recursionquota, 0); + + CHECK(configure_view_acl(NULL, config, "blackhole", &aclconfctx, + ns_g_mctx, &server->blackholeacl)); + if (server->blackholeacl != NULL) + dns_dispatchmgr_setblackhole(ns_g_dispatchmgr, + server->blackholeacl); + + obj = NULL; + result = ns_config_get(maps, "match-mapped-addresses", &obj); + INSIST(result == ISC_R_SUCCESS); + server->aclenv.match_mapped = cfg_obj_asboolean(obj); + + CHECKM(ns_statschannels_configure(ns_g_server, config, &aclconfctx), + "configuring statistics server(s)"); + + /* + * Configure sets of UDP query source ports. + */ + CHECKM(isc_portset_create(ns_g_mctx, &v4portset), + "creating UDP port set"); + CHECKM(isc_portset_create(ns_g_mctx, &v6portset), + "creating UDP port set"); + + usev4ports = NULL; + usev6ports = NULL; + avoidv4ports = NULL; + avoidv6ports = NULL; + + (void)ns_config_get(maps, "use-v4-udp-ports", &usev4ports); + if (usev4ports != NULL) + portset_fromconf(v4portset, usev4ports, ISC_TRUE); + else { + CHECKM(isc_net_getudpportrange(AF_INET, &udpport_low, + &udpport_high), + "get the default UDP/IPv4 port range"); + if (udpport_low == udpport_high) + isc_portset_add(v4portset, udpport_low); + else { + isc_portset_addrange(v4portset, udpport_low, + udpport_high); + } + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "using default UDP/IPv4 port range: [%d, %d]", + udpport_low, udpport_high); + } + (void)ns_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports); + if (avoidv4ports != NULL) + portset_fromconf(v4portset, avoidv4ports, ISC_FALSE); + + (void)ns_config_get(maps, "use-v6-udp-ports", &usev6ports); + if (usev6ports != NULL) + portset_fromconf(v6portset, usev6ports, ISC_TRUE); + else { + CHECKM(isc_net_getudpportrange(AF_INET6, &udpport_low, + &udpport_high), + "get the default UDP/IPv6 port range"); + if (udpport_low == udpport_high) + isc_portset_add(v6portset, udpport_low); + else { + isc_portset_addrange(v6portset, udpport_low, + udpport_high); + } + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "using default UDP/IPv6 port range: [%d, %d]", + udpport_low, udpport_high); + } + (void)ns_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports); + if (avoidv6ports != NULL) + portset_fromconf(v6portset, avoidv6ports, ISC_FALSE); + + dns_dispatchmgr_setavailports(ns_g_dispatchmgr, v4portset, v6portset); + + /* + * Set the EDNS UDP size when we don't match a view. + */ + obj = NULL; + result = ns_config_get(maps, "edns-udp-size", &obj); + INSIST(result == ISC_R_SUCCESS); + udpsize = cfg_obj_asuint32(obj); + if (udpsize < 512) + udpsize = 512; + if (udpsize > 4096) + udpsize = 4096; + ns_g_udpsize = (isc_uint16_t)udpsize; + + /* + * Configure the zone manager. + */ + obj = NULL; + result = ns_config_get(maps, "transfers-in", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj)); + + obj = NULL; + result = ns_config_get(maps, "transfers-per-ns", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj)); + + obj = NULL; + result = ns_config_get(maps, "serial-query-rate", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj)); + + /* + * Determine which port to use for listening for incoming connections. + */ + if (ns_g_port != 0) + listen_port = ns_g_port; + else + CHECKM(ns_config_getport(config, &listen_port), "port"); + + /* + * Find the listen queue depth. + */ + obj = NULL; + result = ns_config_get(maps, "tcp-listen-queue", &obj); + INSIST(result == ISC_R_SUCCESS); + ns_g_listen = cfg_obj_asuint32(obj); + if (ns_g_listen < 3) + ns_g_listen = 3; + + /* + * Configure the interface manager according to the "listen-on" + * statement. + */ + { + const cfg_obj_t *clistenon = NULL; + ns_listenlist_t *listenon = NULL; + + clistenon = NULL; + /* + * Even though listen-on is present in the default + * configuration, we can't use it here, since it isn't + * used if we're in lwresd mode. This way is easier. + */ + if (options != NULL) + (void)cfg_map_get(options, "listen-on", &clistenon); + if (clistenon != NULL) { + result = ns_listenlist_fromconfig(clistenon, + config, + &aclconfctx, + ns_g_mctx, + &listenon); + } else if (!ns_g_lwresdonly) { + /* + * Not specified, use default. + */ + CHECK(ns_listenlist_default(ns_g_mctx, listen_port, + ISC_TRUE, &listenon)); + } + if (listenon != NULL) { + ns_interfacemgr_setlistenon4(server->interfacemgr, + listenon); + ns_listenlist_detach(&listenon); + } + } + /* + * Ditto for IPv6. + */ + { + const cfg_obj_t *clistenon = NULL; + ns_listenlist_t *listenon = NULL; + + if (options != NULL) + (void)cfg_map_get(options, "listen-on-v6", &clistenon); + if (clistenon != NULL) { + result = ns_listenlist_fromconfig(clistenon, + config, + &aclconfctx, + ns_g_mctx, + &listenon); + } else if (!ns_g_lwresdonly) { + /* + * Not specified, use default. + */ + CHECK(ns_listenlist_default(ns_g_mctx, listen_port, + ISC_FALSE, &listenon)); + } + if (listenon != NULL) { + ns_interfacemgr_setlistenon6(server->interfacemgr, + listenon); + ns_listenlist_detach(&listenon); + } + } + + /* + * Rescan the interface list to pick up changes in the + * listen-on option. It's important that we do this before we try + * to configure the query source, since the dispatcher we use might + * be shared with an interface. + */ + scan_interfaces(server, ISC_TRUE); + + /* + * Arrange for further interface scanning to occur periodically + * as specified by the "interface-interval" option. + */ + obj = NULL; + result = ns_config_get(maps, "interface-interval", &obj); + INSIST(result == ISC_R_SUCCESS); + interface_interval = cfg_obj_asuint32(obj) * 60; + if (interface_interval == 0) { + CHECK(isc_timer_reset(server->interface_timer, + isc_timertype_inactive, + NULL, NULL, ISC_TRUE)); + } else if (server->interface_interval != interface_interval) { + isc_interval_set(&interval, interface_interval, 0); + CHECK(isc_timer_reset(server->interface_timer, + isc_timertype_ticker, + NULL, &interval, ISC_FALSE)); + } + server->interface_interval = interface_interval; + + /* + * Configure the dialup heartbeat timer. + */ + obj = NULL; + result = ns_config_get(maps, "heartbeat-interval", &obj); + INSIST(result == ISC_R_SUCCESS); + heartbeat_interval = cfg_obj_asuint32(obj) * 60; + if (heartbeat_interval == 0) { + CHECK(isc_timer_reset(server->heartbeat_timer, + isc_timertype_inactive, + NULL, NULL, ISC_TRUE)); + } else if (server->heartbeat_interval != heartbeat_interval) { + isc_interval_set(&interval, heartbeat_interval, 0); + CHECK(isc_timer_reset(server->heartbeat_timer, + isc_timertype_ticker, + NULL, &interval, ISC_FALSE)); + } + server->heartbeat_interval = heartbeat_interval; + + isc_interval_set(&interval, 1200, 0); + CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL, + &interval, ISC_FALSE)); + + /* + * Configure and freeze all explicit views. Explicit + * views that have zones were already created at parsing + * time, but views with no zones must be created here. + */ + views = NULL; + (void)cfg_map_get(config, "view", &views); + for (element = cfg_list_first(views); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *vconfig = cfg_listelt_value(element); + view = NULL; + + CHECK(create_view(vconfig, &viewlist, &view)); + INSIST(view != NULL); + CHECK(configure_view(view, config, vconfig, + ns_g_mctx, &aclconfctx, ISC_TRUE)); + dns_view_freeze(view); + dns_view_detach(&view); + } + + /* + * Make sure we have a default view if and only if there + * were no explicit views. + */ + if (views == NULL) { + /* + * No explicit views; there ought to be a default view. + * There may already be one created as a side effect + * of zone statements, or we may have to create one. + * In either case, we need to configure and freeze it. + */ + CHECK(create_view(NULL, &viewlist, &view)); + CHECK(configure_view(view, config, NULL, ns_g_mctx, + &aclconfctx, ISC_TRUE)); + dns_view_freeze(view); + dns_view_detach(&view); + } + + /* + * Create (or recreate) the built-in views. Currently + * there is only one, the _bind view. + */ + builtin_views = NULL; + RUNTIME_CHECK(cfg_map_get(ns_g_config, "view", + &builtin_views) == ISC_R_SUCCESS); + for (element = cfg_list_first(builtin_views); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *vconfig = cfg_listelt_value(element); + CHECK(create_view(vconfig, &viewlist, &view)); + CHECK(configure_view(view, config, vconfig, ns_g_mctx, + &aclconfctx, ISC_FALSE)); + dns_view_freeze(view); + dns_view_detach(&view); + view = NULL; + } + + /* + * Swap our new view list with the production one. + */ + tmpviewlist = server->viewlist; + server->viewlist = viewlist; + viewlist = tmpviewlist; + + /* + * Load the TKEY information from the configuration. + */ + if (options != NULL) { + dns_tkeyctx_t *t = NULL; + CHECKM(ns_tkeyctx_fromconfig(options, ns_g_mctx, ns_g_entropy, + &t), + "configuring TKEY"); + if (server->tkeyctx != NULL) + dns_tkeyctx_destroy(&server->tkeyctx); + server->tkeyctx = t; + } + + /* + * Bind the control port(s). + */ + CHECKM(ns_controls_configure(ns_g_server->controls, config, + &aclconfctx), + "binding control channel(s)"); + + /* + * Bind the lwresd port(s). + */ + CHECKM(ns_lwresd_configure(ns_g_mctx, config), + "binding lightweight resolver ports"); + + /* + * Open the source of entropy. + */ + if (first_time) { + obj = NULL; + result = ns_config_get(maps, "random-device", &obj); + if (result != ISC_R_SUCCESS) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "no source of entropy found"); + } else { + const char *randomdev = cfg_obj_asstring(obj); + result = isc_entropy_createfilesource(ns_g_entropy, + randomdev); + if (result != ISC_R_SUCCESS) + isc_log_write(ns_g_lctx, + NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, + ISC_LOG_INFO, + "could not open entropy source " + "%s: %s", + randomdev, + isc_result_totext(result)); +#ifdef PATH_RANDOMDEV + if (ns_g_fallbackentropy != NULL) { + if (result != ISC_R_SUCCESS) { + isc_log_write(ns_g_lctx, + NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, + ISC_LOG_INFO, + "using pre-chroot entropy source " + "%s", + PATH_RANDOMDEV); + isc_entropy_detach(&ns_g_entropy); + isc_entropy_attach(ns_g_fallbackentropy, + &ns_g_entropy); + } + isc_entropy_detach(&ns_g_fallbackentropy); + } +#endif + } + } + + /* + * Relinquish root privileges. + */ + if (first_time) + ns_os_changeuser(); + + /* + * Check that the working directory is writable. + */ + if (access(".", W_OK) != 0) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "the working directory is not writable"); + } + + /* + * Configure the logging system. + * + * Do this after changing UID to make sure that any log + * files specified in named.conf get created by the + * unprivileged user, not root. + */ + if (ns_g_logstderr) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "ignoring config file logging " + "statement due to -g option"); + } else { + const cfg_obj_t *logobj = NULL; + isc_logconfig_t *logc = NULL; + + CHECKM(isc_logconfig_create(ns_g_lctx, &logc), + "creating new logging configuration"); + + logobj = NULL; + (void)cfg_map_get(config, "logging", &logobj); + if (logobj != NULL) { + CHECKM(ns_log_configure(logc, logobj), + "configuring logging"); + } else { + CHECKM(ns_log_setdefaultchannels(logc), + "setting up default logging channels"); + CHECKM(ns_log_setunmatchedcategory(logc), + "setting up default 'category unmatched'"); + CHECKM(ns_log_setdefaultcategory(logc), + "setting up default 'category default'"); + } + + result = isc_logconfig_use(ns_g_lctx, logc); + if (result != ISC_R_SUCCESS) { + isc_logconfig_destroy(&logc); + CHECKM(result, "installing logging configuration"); + } + + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1), + "now using logging configuration from " + "config file"); + } + + /* + * Set the default value of the query logging flag depending + * whether a "queries" category has been defined. This is + * a disgusting hack, but we need to do this for BIND 8 + * compatibility. + */ + if (first_time) { + const cfg_obj_t *logobj = NULL; + const cfg_obj_t *categories = NULL; + + obj = NULL; + if (ns_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) { + server->log_queries = cfg_obj_asboolean(obj); + } else { + + (void)cfg_map_get(config, "logging", &logobj); + if (logobj != NULL) + (void)cfg_map_get(logobj, "category", + &categories); + if (categories != NULL) { + const cfg_listelt_t *element; + for (element = cfg_list_first(categories); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *catobj; + const char *str; + + obj = cfg_listelt_value(element); + catobj = cfg_tuple_get(obj, "name"); + str = cfg_obj_asstring(catobj); + if (strcasecmp(str, "queries") == 0) + server->log_queries = ISC_TRUE; + } + } + } + } + + obj = NULL; + if (ns_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS) + if (cfg_obj_isvoid(obj)) + ns_os_writepidfile(NULL, first_time); + else + ns_os_writepidfile(cfg_obj_asstring(obj), first_time); + else if (ns_g_lwresdonly) + ns_os_writepidfile(lwresd_g_defaultpidfile, first_time); + else + ns_os_writepidfile(ns_g_defaultpidfile, first_time); + + obj = NULL; + if (options != NULL && + cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS) + ns_g_memstatistics = cfg_obj_asboolean(obj); + else + ns_g_memstatistics = + ISC_TF((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0); + + obj = NULL; + if (ns_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS) + ns_main_setmemstats(cfg_obj_asstring(obj)); + else if (ns_g_memstatistics) + ns_main_setmemstats("named.memstats"); + else + ns_main_setmemstats(NULL); + + obj = NULL; + result = ns_config_get(maps, "statistics-file", &obj); + INSIST(result == ISC_R_SUCCESS); + CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)), + "strdup"); + + obj = NULL; + result = ns_config_get(maps, "dump-file", &obj); + INSIST(result == ISC_R_SUCCESS); + CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)), + "strdup"); + + obj = NULL; + result = ns_config_get(maps, "recursing-file", &obj); + INSIST(result == ISC_R_SUCCESS); + CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)), + "strdup"); + + obj = NULL; + result = ns_config_get(maps, "version", &obj); + if (result == ISC_R_SUCCESS) { + CHECKM(setoptstring(server, &server->version, obj), "strdup"); + server->version_set = ISC_TRUE; + } else { + server->version_set = ISC_FALSE; + } + + obj = NULL; + result = ns_config_get(maps, "hostname", &obj); + if (result == ISC_R_SUCCESS) { + CHECKM(setoptstring(server, &server->hostname, obj), "strdup"); + server->hostname_set = ISC_TRUE; + } else { + server->hostname_set = ISC_FALSE; + } + + obj = NULL; + result = ns_config_get(maps, "server-id", &obj); + server->server_usehostname = ISC_FALSE; + if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) { + /* The parser translates "hostname" to ISC_TRUE */ + server->server_usehostname = cfg_obj_asboolean(obj); + result = setstring(server, &server->server_id, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + } else if (result == ISC_R_SUCCESS) { + /* Found a quoted string */ + CHECKM(setoptstring(server, &server->server_id, obj), "strdup"); + } else { + result = setstring(server, &server->server_id, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + } + + obj = NULL; + result = ns_config_get(maps, "flush-zones-on-shutdown", &obj); + if (result == ISC_R_SUCCESS) { + server->flushonshutdown = cfg_obj_asboolean(obj); + } else { + server->flushonshutdown = ISC_FALSE; + } + + result = ISC_R_SUCCESS; + + cleanup: + if (v4portset != NULL) + isc_portset_destroy(ns_g_mctx, &v4portset); + + if (v6portset != NULL) + isc_portset_destroy(ns_g_mctx, &v6portset); + + cfg_aclconfctx_destroy(&aclconfctx); + + if (parser != NULL) { + if (config != NULL) + cfg_obj_destroy(parser, &config); + cfg_parser_destroy(&parser); + } + + if (view != NULL) + dns_view_detach(&view); + + /* + * This cleans up either the old production view list + * or our temporary list depending on whether they + * were swapped above or not. + */ + for (view = ISC_LIST_HEAD(viewlist); + view != NULL; + view = view_next) { + view_next = ISC_LIST_NEXT(view, link); + ISC_LIST_UNLINK(viewlist, view, link); + if (result == ISC_R_SUCCESS && + strcmp(view->name, "_bind") != 0) + (void)dns_zt_apply(view->zonetable, ISC_FALSE, + removed, view); + dns_view_detach(&view); + } + + /* + * Adjust the listening interfaces in accordance with the source + * addresses specified in views and zones. + */ + if (isc_net_probeipv6() == ISC_R_SUCCESS) + adjust_interfaces(server, ns_g_mctx); + + /* Relinquish exclusive access to configuration data. */ + isc_task_endexclusive(server->task); + + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, + ISC_LOG_DEBUG(1), "load_configuration: %s", + isc_result_totext(result)); + + return (result); +} + +static isc_result_t +load_zones(ns_server_t *server, isc_boolean_t stop) { + isc_result_t result; + dns_view_t *view; + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + /* + * Load zone data from disk. + */ + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + CHECK(dns_view_load(view, stop)); + } + + /* + * Force zone maintenance. Do this after loading + * so that we know when we need to force AXFR of + * slave zones whose master files are missing. + */ + CHECK(dns_zonemgr_forcemaint(server->zonemgr)); + cleanup: + isc_task_endexclusive(server->task); + return (result); +} + +static isc_result_t +load_new_zones(ns_server_t *server, isc_boolean_t stop) { + isc_result_t result; + dns_view_t *view; + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + /* + * Load zone data from disk. + */ + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + CHECK(dns_view_loadnew(view, stop)); + } + /* + * Force zone maintenance. Do this after loading + * so that we know when we need to force AXFR of + * slave zones whose master files are missing. + */ + dns_zonemgr_resumexfrs(server->zonemgr); + cleanup: + isc_task_endexclusive(server->task); + return (result); +} + +static void +run_server(isc_task_t *task, isc_event_t *event) { + isc_result_t result; + ns_server_t *server = (ns_server_t *)event->ev_arg; + + INSIST(task == server->task); + + isc_event_free(&event); + + CHECKFATAL(dns_dispatchmgr_create(ns_g_mctx, ns_g_entropy, + &ns_g_dispatchmgr), + "creating dispatch manager"); + + dns_dispatchmgr_setstats(ns_g_dispatchmgr, server->resolverstats); + + CHECKFATAL(ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr, + ns_g_socketmgr, ns_g_dispatchmgr, + &server->interfacemgr), + "creating interface manager"); + + CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive, + NULL, NULL, server->task, + interface_timer_tick, + server, &server->interface_timer), + "creating interface timer"); + + CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive, + NULL, NULL, server->task, + heartbeat_timer_tick, + server, &server->heartbeat_timer), + "creating heartbeat timer"); + + CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive, + NULL, NULL, server->task, pps_timer_tick, + server, &server->pps_timer), + "creating pps timer"); + + CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser), + "creating default configuration parser"); + + if (ns_g_lwresdonly) + CHECKFATAL(load_configuration(lwresd_g_conffile, server, + ISC_TRUE), + "loading configuration"); + else + CHECKFATAL(load_configuration(ns_g_conffile, server, ISC_TRUE), + "loading configuration"); + + isc_hash_init(); + + CHECKFATAL(load_zones(server, ISC_FALSE), "loading zones"); + + ns_os_started(); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, + ISC_LOG_NOTICE, "running"); +} + +void +ns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush) { + + REQUIRE(NS_SERVER_VALID(server)); + + server->flushonshutdown = flush; +} + +static void +shutdown_server(isc_task_t *task, isc_event_t *event) { + isc_result_t result; + dns_view_t *view, *view_next; + ns_server_t *server = (ns_server_t *)event->ev_arg; + isc_boolean_t flush = server->flushonshutdown; + + UNUSED(task); + INSIST(task == server->task); + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, + ISC_LOG_INFO, "shutting down%s", + flush ? ": flushing changes" : ""); + + ns_statschannels_shutdown(server); + ns_controls_shutdown(server->controls); + end_reserved_dispatches(server, ISC_TRUE); + + cfg_obj_destroy(ns_g_parser, &ns_g_config); + cfg_parser_destroy(&ns_g_parser); + + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = view_next) { + view_next = ISC_LIST_NEXT(view, link); + ISC_LIST_UNLINK(server->viewlist, view, link); + if (flush) + dns_view_flushanddetach(&view); + else + dns_view_detach(&view); + } + + isc_timer_detach(&server->interface_timer); + isc_timer_detach(&server->heartbeat_timer); + isc_timer_detach(&server->pps_timer); + + ns_interfacemgr_shutdown(server->interfacemgr); + ns_interfacemgr_detach(&server->interfacemgr); + + dns_dispatchmgr_destroy(&ns_g_dispatchmgr); + + dns_zonemgr_shutdown(server->zonemgr); + + if (server->blackholeacl != NULL) + dns_acl_detach(&server->blackholeacl); + + dns_db_detach(&server->in_roothints); + + isc_task_endexclusive(server->task); + + isc_task_detach(&server->task); + + isc_event_free(&event); +} + +void +ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { + isc_result_t result; + + ns_server_t *server = isc_mem_get(mctx, sizeof(*server)); + if (server == NULL) + fatal("allocating server object", ISC_R_NOMEMORY); + + server->mctx = mctx; + server->task = NULL; + + /* Initialize configuration data with default values. */ + + result = isc_quota_init(&server->xfroutquota, 10); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + result = isc_quota_init(&server->tcpquota, 10); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + result = isc_quota_init(&server->recursionquota, 100); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + result = dns_aclenv_init(mctx, &server->aclenv); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + /* Initialize server data structures. */ + server->zonemgr = NULL; + server->interfacemgr = NULL; + ISC_LIST_INIT(server->viewlist); + server->in_roothints = NULL; + server->blackholeacl = NULL; + + CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL, + &server->in_roothints), + "setting up root hints"); + + CHECKFATAL(isc_mutex_init(&server->reload_event_lock), + "initializing reload event lock"); + server->reload_event = + isc_event_allocate(ns_g_mctx, server, + NS_EVENT_RELOAD, + ns_server_reload, + server, + sizeof(isc_event_t)); + CHECKFATAL(server->reload_event == NULL ? + ISC_R_NOMEMORY : ISC_R_SUCCESS, + "allocating reload event"); + + CHECKFATAL(dst_lib_init(ns_g_mctx, ns_g_entropy, ISC_ENTROPY_GOODONLY), + "initializing DST"); + + server->tkeyctx = NULL; + CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, ns_g_entropy, + &server->tkeyctx), + "creating TKEY context"); + + /* + * Setup the server task, which is responsible for coordinating + * startup and shutdown of the server. + */ + CHECKFATAL(isc_task_create(ns_g_taskmgr, 0, &server->task), + "creating server task"); + isc_task_setname(server->task, "server", server); + CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server), + "isc_task_onshutdown"); + CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server), + "isc_app_onrun"); + + server->interface_timer = NULL; + server->heartbeat_timer = NULL; + server->pps_timer = NULL; + + server->interface_interval = 0; + server->heartbeat_interval = 0; + + CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr, + ns_g_socketmgr, &server->zonemgr), + "dns_zonemgr_create"); + + server->statsfile = isc_mem_strdup(server->mctx, "named.stats"); + CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, + "isc_mem_strdup"); + server->nsstats = NULL; + server->rcvquerystats = NULL; + server->opcodestats = NULL; + server->zonestats = NULL; + server->resolverstats = NULL; + server->sockstats = NULL; + CHECKFATAL(isc_stats_create(server->mctx, &server->sockstats, + isc_sockstatscounter_max), + "isc_stats_create"); + isc_socketmgr_setstats(ns_g_socketmgr, server->sockstats); + + server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db"); + CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, + "isc_mem_strdup"); + + server->recfile = isc_mem_strdup(server->mctx, "named.recursing"); + CHECKFATAL(server->recfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, + "isc_mem_strdup"); + + server->hostname_set = ISC_FALSE; + server->hostname = NULL; + server->version_set = ISC_FALSE; + server->version = NULL; + server->server_usehostname = ISC_FALSE; + server->server_id = NULL; + + CHECKFATAL(isc_stats_create(ns_g_mctx, &server->nsstats, + dns_nsstatscounter_max), + "dns_stats_create (server)"); + + CHECKFATAL(dns_rdatatypestats_create(ns_g_mctx, + &server->rcvquerystats), + "dns_stats_create (rcvquery)"); + + CHECKFATAL(dns_opcodestats_create(ns_g_mctx, &server->opcodestats), + "dns_stats_create (opcode)"); + + CHECKFATAL(isc_stats_create(ns_g_mctx, &server->zonestats, + dns_zonestatscounter_max), + "dns_stats_create (zone)"); + + CHECKFATAL(isc_stats_create(ns_g_mctx, &server->resolverstats, + dns_resstatscounter_max), + "dns_stats_create (resolver)"); + + server->flushonshutdown = ISC_FALSE; + server->log_queries = ISC_FALSE; + + server->controls = NULL; + CHECKFATAL(ns_controls_create(server, &server->controls), + "ns_controls_create"); + server->dispatchgen = 0; + ISC_LIST_INIT(server->dispatches); + + ISC_LIST_INIT(server->statschannels); + + server->magic = NS_SERVER_MAGIC; + *serverp = server; +} + +void +ns_server_destroy(ns_server_t **serverp) { + ns_server_t *server = *serverp; + REQUIRE(NS_SERVER_VALID(server)); + + ns_controls_destroy(&server->controls); + + isc_stats_detach(&server->nsstats); + dns_stats_detach(&server->rcvquerystats); + dns_stats_detach(&server->opcodestats); + isc_stats_detach(&server->zonestats); + isc_stats_detach(&server->resolverstats); + isc_stats_detach(&server->sockstats); + + isc_mem_free(server->mctx, server->statsfile); + isc_mem_free(server->mctx, server->dumpfile); + isc_mem_free(server->mctx, server->recfile); + + if (server->version != NULL) + isc_mem_free(server->mctx, server->version); + if (server->hostname != NULL) + isc_mem_free(server->mctx, server->hostname); + if (server->server_id != NULL) + isc_mem_free(server->mctx, server->server_id); + + dns_zonemgr_detach(&server->zonemgr); + + if (server->tkeyctx != NULL) + dns_tkeyctx_destroy(&server->tkeyctx); + + dst_lib_destroy(); + + isc_event_free(&server->reload_event); + + INSIST(ISC_LIST_EMPTY(server->viewlist)); + + dns_aclenv_destroy(&server->aclenv); + + isc_quota_destroy(&server->recursionquota); + isc_quota_destroy(&server->tcpquota); + isc_quota_destroy(&server->xfroutquota); + + server->magic = 0; + isc_mem_put(server->mctx, server, sizeof(*server)); + *serverp = NULL; +} + +static void +fatal(const char *msg, isc_result_t result) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, + ISC_LOG_CRITICAL, "%s: %s", msg, + isc_result_totext(result)); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, + ISC_LOG_CRITICAL, "exiting (due to fatal error)"); + exit(1); +} + +static void +start_reserved_dispatches(ns_server_t *server) { + + REQUIRE(NS_SERVER_VALID(server)); + + server->dispatchgen++; +} + +static void +end_reserved_dispatches(ns_server_t *server, isc_boolean_t all) { + ns_dispatch_t *dispatch, *nextdispatch; + + REQUIRE(NS_SERVER_VALID(server)); + + for (dispatch = ISC_LIST_HEAD(server->dispatches); + dispatch != NULL; + dispatch = nextdispatch) { + nextdispatch = ISC_LIST_NEXT(dispatch, link); + if (!all && server->dispatchgen == dispatch-> dispatchgen) + continue; + ISC_LIST_UNLINK(server->dispatches, dispatch, link); + dns_dispatch_detach(&dispatch->dispatch); + isc_mem_put(server->mctx, dispatch, sizeof(*dispatch)); + } +} + +void +ns_add_reserved_dispatch(ns_server_t *server, const isc_sockaddr_t *addr) { + ns_dispatch_t *dispatch; + in_port_t port; + char addrbuf[ISC_SOCKADDR_FORMATSIZE]; + isc_result_t result; + unsigned int attrs, attrmask; + + REQUIRE(NS_SERVER_VALID(server)); + + port = isc_sockaddr_getport(addr); + if (port == 0 || port >= 1024) + return; + + for (dispatch = ISC_LIST_HEAD(server->dispatches); + dispatch != NULL; + dispatch = ISC_LIST_NEXT(dispatch, link)) { + if (isc_sockaddr_equal(&dispatch->addr, addr)) + break; + } + if (dispatch != NULL) { + dispatch->dispatchgen = server->dispatchgen; + return; + } + + dispatch = isc_mem_get(server->mctx, sizeof(*dispatch)); + if (dispatch == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup; + } + + dispatch->addr = *addr; + dispatch->dispatchgen = server->dispatchgen; + dispatch->dispatch = NULL; + + attrs = 0; + attrs |= DNS_DISPATCHATTR_UDP; + switch (isc_sockaddr_pf(addr)) { + case AF_INET: + attrs |= DNS_DISPATCHATTR_IPV4; + break; + case AF_INET6: + attrs |= DNS_DISPATCHATTR_IPV6; + break; + default: + result = ISC_R_NOTIMPLEMENTED; + goto cleanup; + } + attrmask = 0; + attrmask |= DNS_DISPATCHATTR_UDP; + attrmask |= DNS_DISPATCHATTR_TCP; + attrmask |= DNS_DISPATCHATTR_IPV4; + attrmask |= DNS_DISPATCHATTR_IPV6; + + result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr, + ns_g_taskmgr, &dispatch->addr, 4096, + 1000, 32768, 16411, 16433, + attrs, attrmask, &dispatch->dispatch); + if (result != ISC_R_SUCCESS) + goto cleanup; + + ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link); + + return; + + cleanup: + if (dispatch != NULL) + isc_mem_put(server->mctx, dispatch, sizeof(*dispatch)); + isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_WARNING, + "unable to create dispatch for reserved port %s: %s", + addrbuf, isc_result_totext(result)); +} + + +static isc_result_t +loadconfig(ns_server_t *server) { + isc_result_t result; + start_reserved_dispatches(server); + result = load_configuration(ns_g_lwresdonly ? + lwresd_g_conffile : ns_g_conffile, + server, ISC_FALSE); + if (result == ISC_R_SUCCESS) { + end_reserved_dispatches(server, ISC_FALSE); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "reloading configuration succeeded"); + } else { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "reloading configuration failed: %s", + isc_result_totext(result)); + } + return (result); +} + +static isc_result_t +reload(ns_server_t *server) { + isc_result_t result; + CHECK(loadconfig(server)); + + result = load_zones(server, ISC_FALSE); + if (result == ISC_R_SUCCESS) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "reloading zones succeeded"); + else + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "reloading zones failed: %s", + isc_result_totext(result)); + + cleanup: + return (result); +} + +static void +reconfig(ns_server_t *server) { + isc_result_t result; + CHECK(loadconfig(server)); + + result = load_new_zones(server, ISC_FALSE); + if (result == ISC_R_SUCCESS) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "any newly configured zones are now loaded"); + else + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "loading new zones failed: %s", + isc_result_totext(result)); + + cleanup: ; +} + +/* + * Handle a reload event (from SIGHUP). + */ +static void +ns_server_reload(isc_task_t *task, isc_event_t *event) { + ns_server_t *server = (ns_server_t *)event->ev_arg; + + INSIST(task = server->task); + UNUSED(task); + + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "received SIGHUP signal to reload zones"); + (void)reload(server); + + LOCK(&server->reload_event_lock); + INSIST(server->reload_event == NULL); + server->reload_event = event; + UNLOCK(&server->reload_event_lock); +} + +void +ns_server_reloadwanted(ns_server_t *server) { + LOCK(&server->reload_event_lock); + if (server->reload_event != NULL) + isc_task_send(server->task, &server->reload_event); + UNLOCK(&server->reload_event_lock); +} + +static char * +next_token(char **stringp, const char *delim) { + char *res; + + do { + res = strsep(stringp, delim); + if (res == NULL) + break; + } while (*res == '\0'); + return (res); +} + +/* + * Find the zone specified in the control channel command 'args', + * if any. If a zone is specified, point '*zonep' at it, otherwise + * set '*zonep' to NULL. + */ +static isc_result_t +zone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep) { + char *input, *ptr; + const char *zonetxt; + char *classtxt; + const char *viewtxt = NULL; + dns_fixedname_t name; + isc_result_t result; + isc_buffer_t buf; + dns_view_t *view = NULL; + dns_rdataclass_t rdclass; + + REQUIRE(zonep != NULL && *zonep == NULL); + + input = args; + + /* Skip the command name. */ + ptr = next_token(&input, " \t"); + if (ptr == NULL) + return (ISC_R_UNEXPECTEDEND); + + /* Look for the zone name. */ + zonetxt = next_token(&input, " \t"); + if (zonetxt == NULL) + return (ISC_R_SUCCESS); + + /* Look for the optional class name. */ + classtxt = next_token(&input, " \t"); + if (classtxt != NULL) { + /* Look for the optional view name. */ + viewtxt = next_token(&input, " \t"); + } + + isc_buffer_init(&buf, zonetxt, strlen(zonetxt)); + isc_buffer_add(&buf, strlen(zonetxt)); + dns_fixedname_init(&name); + result = dns_name_fromtext(dns_fixedname_name(&name), + &buf, dns_rootname, ISC_FALSE, NULL); + if (result != ISC_R_SUCCESS) + goto fail1; + + if (classtxt != NULL) { + isc_textregion_t r; + r.base = classtxt; + r.length = strlen(classtxt); + result = dns_rdataclass_fromtext(&rdclass, &r); + if (result != ISC_R_SUCCESS) + goto fail1; + } else + rdclass = dns_rdataclass_in; + + if (viewtxt == NULL) { + result = dns_viewlist_findzone(&server->viewlist, + dns_fixedname_name(&name), + ISC_TF(classtxt == NULL), + rdclass, zonep); + } else { + result = dns_viewlist_find(&server->viewlist, viewtxt, + rdclass, &view); + if (result != ISC_R_SUCCESS) + goto fail1; + + result = dns_zt_find(view->zonetable, dns_fixedname_name(&name), + 0, NULL, zonep); + dns_view_detach(&view); + } + + /* Partial match? */ + if (result != ISC_R_SUCCESS && *zonep != NULL) + dns_zone_detach(zonep); + fail1: + return (result); +} + +/* + * Act on a "retransfer" command from the command channel. + */ +isc_result_t +ns_server_retransfercommand(ns_server_t *server, char *args) { + isc_result_t result; + dns_zone_t *zone = NULL; + dns_zonetype_t type; + + result = zone_from_args(server, args, &zone); + if (result != ISC_R_SUCCESS) + return (result); + if (zone == NULL) + return (ISC_R_UNEXPECTEDEND); + type = dns_zone_gettype(zone); + if (type == dns_zone_slave || type == dns_zone_stub) + dns_zone_forcereload(zone); + else + result = ISC_R_NOTFOUND; + dns_zone_detach(&zone); + return (result); +} + +/* + * Act on a "reload" command from the command channel. + */ +isc_result_t +ns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t *text) { + isc_result_t result; + dns_zone_t *zone = NULL; + dns_zonetype_t type; + const char *msg = NULL; + + result = zone_from_args(server, args, &zone); + if (result != ISC_R_SUCCESS) + return (result); + if (zone == NULL) { + result = reload(server); + if (result == ISC_R_SUCCESS) + msg = "server reload successful"; + } else { + type = dns_zone_gettype(zone); + if (type == dns_zone_slave || type == dns_zone_stub) { + dns_zone_refresh(zone); + dns_zone_detach(&zone); + msg = "zone refresh queued"; + } else { + result = dns_zone_load(zone); + dns_zone_detach(&zone); + switch (result) { + case ISC_R_SUCCESS: + msg = "zone reload successful"; + break; + case DNS_R_CONTINUE: + msg = "zone reload queued"; + result = ISC_R_SUCCESS; + break; + case DNS_R_UPTODATE: + msg = "zone reload up-to-date"; + result = ISC_R_SUCCESS; + break; + default: + /* failure message will be generated by rndc */ + break; + } + } + } + if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text)) + isc_buffer_putmem(text, (const unsigned char *)msg, + strlen(msg) + 1); + return (result); +} + +/* + * Act on a "reconfig" command from the command channel. + */ +isc_result_t +ns_server_reconfigcommand(ns_server_t *server, char *args) { + UNUSED(args); + + reconfig(server); + return (ISC_R_SUCCESS); +} + +/* + * Act on a "notify" command from the command channel. + */ +isc_result_t +ns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t *text) { + isc_result_t result; + dns_zone_t *zone = NULL; + const unsigned char msg[] = "zone notify queued"; + + result = zone_from_args(server, args, &zone); + if (result != ISC_R_SUCCESS) + return (result); + if (zone == NULL) + return (ISC_R_UNEXPECTEDEND); + + dns_zone_notify(zone); + dns_zone_detach(&zone); + if (sizeof(msg) <= isc_buffer_availablelength(text)) + isc_buffer_putmem(text, msg, sizeof(msg)); + + return (ISC_R_SUCCESS); +} + +/* + * Act on a "refresh" command from the command channel. + */ +isc_result_t +ns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t *text) { + isc_result_t result; + dns_zone_t *zone = NULL; + const unsigned char msg1[] = "zone refresh queued"; + const unsigned char msg2[] = "not a slave or stub zone"; + dns_zonetype_t type; + + result = zone_from_args(server, args, &zone); + if (result != ISC_R_SUCCESS) + return (result); + if (zone == NULL) + return (ISC_R_UNEXPECTEDEND); + + type = dns_zone_gettype(zone); + if (type == dns_zone_slave || type == dns_zone_stub) { + dns_zone_refresh(zone); + dns_zone_detach(&zone); + if (sizeof(msg1) <= isc_buffer_availablelength(text)) + isc_buffer_putmem(text, msg1, sizeof(msg1)); + return (ISC_R_SUCCESS); + } + + dns_zone_detach(&zone); + if (sizeof(msg2) <= isc_buffer_availablelength(text)) + isc_buffer_putmem(text, msg2, sizeof(msg2)); + return (ISC_R_FAILURE); +} + +isc_result_t +ns_server_togglequerylog(ns_server_t *server) { + server->log_queries = server->log_queries ? ISC_FALSE : ISC_TRUE; + + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "query logging is now %s", + server->log_queries ? "on" : "off"); + return (ISC_R_SUCCESS); +} + +static isc_result_t +ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config, + cfg_aclconfctx_t *actx, + isc_mem_t *mctx, ns_listenlist_t **target) +{ + isc_result_t result; + const cfg_listelt_t *element; + ns_listenlist_t *dlist = NULL; + + REQUIRE(target != NULL && *target == NULL); + + result = ns_listenlist_create(mctx, &dlist); + if (result != ISC_R_SUCCESS) + return (result); + + for (element = cfg_list_first(listenlist); + element != NULL; + element = cfg_list_next(element)) + { + ns_listenelt_t *delt = NULL; + const cfg_obj_t *listener = cfg_listelt_value(element); + result = ns_listenelt_fromconfig(listener, config, actx, + mctx, &delt); + if (result != ISC_R_SUCCESS) + goto cleanup; + ISC_LIST_APPEND(dlist->elts, delt, link); + } + *target = dlist; + return (ISC_R_SUCCESS); + + cleanup: + ns_listenlist_detach(&dlist); + return (result); +} + +/* + * Create a listen list from the corresponding configuration + * data structure. + */ +static isc_result_t +ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, + cfg_aclconfctx_t *actx, + isc_mem_t *mctx, ns_listenelt_t **target) +{ + isc_result_t result; + const cfg_obj_t *portobj; + in_port_t port; + ns_listenelt_t *delt = NULL; + REQUIRE(target != NULL && *target == NULL); + + portobj = cfg_tuple_get(listener, "port"); + if (!cfg_obj_isuint32(portobj)) { + if (ns_g_port != 0) { + port = ns_g_port; + } else { + result = ns_config_getport(config, &port); + if (result != ISC_R_SUCCESS) + return (result); + } + } else { + if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) { + cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, + "port value '%u' is out of range", + cfg_obj_asuint32(portobj)); + return (ISC_R_RANGE); + } + port = (in_port_t)cfg_obj_asuint32(portobj); + } + + result = ns_listenelt_create(mctx, port, NULL, &delt); + if (result != ISC_R_SUCCESS) + return (result); + + result = cfg_acl_fromconfig(cfg_tuple_get(listener, "acl"), + config, ns_g_lctx, actx, mctx, 0, + &delt->acl); + if (result != ISC_R_SUCCESS) { + ns_listenelt_destroy(delt); + return (result); + } + *target = delt; + return (ISC_R_SUCCESS); +} + +isc_result_t +ns_server_dumpstats(ns_server_t *server) { + isc_result_t result; + FILE *fp = NULL; + + CHECKMF(isc_stdio_open(server->statsfile, "a", &fp), + "could not open statistics dump file", server->statsfile); + + result = ns_stats_dump(server, fp); + CHECK(result); + + cleanup: + if (fp != NULL) + (void)isc_stdio_close(fp); + if (result == ISC_R_SUCCESS) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "dumpstats complete"); + else + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "dumpstats failed: %s", + dns_result_totext(result)); + return (result); +} + +static isc_result_t +add_zone_tolist(dns_zone_t *zone, void *uap) { + struct dumpcontext *dctx = uap; + struct zonelistentry *zle; + + zle = isc_mem_get(dctx->mctx, sizeof *zle); + if (zle == NULL) + return (ISC_R_NOMEMORY); + zle->zone = NULL; + dns_zone_attach(zone, &zle->zone); + ISC_LINK_INIT(zle, link); + ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link); + return (ISC_R_SUCCESS); +} + +static isc_result_t +add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) { + struct viewlistentry *vle; + isc_result_t result = ISC_R_SUCCESS; + + /* + * Prevent duplicate views. + */ + for (vle = ISC_LIST_HEAD(dctx->viewlist); + vle != NULL; + vle = ISC_LIST_NEXT(vle, link)) + if (vle->view == view) + return (ISC_R_SUCCESS); + + vle = isc_mem_get(dctx->mctx, sizeof *vle); + if (vle == NULL) + return (ISC_R_NOMEMORY); + vle->view = NULL; + dns_view_attach(view, &vle->view); + ISC_LINK_INIT(vle, link); + ISC_LIST_INIT(vle->zonelist); + ISC_LIST_APPEND(dctx->viewlist, vle, link); + if (dctx->dumpzones) + result = dns_zt_apply(view->zonetable, ISC_TRUE, + add_zone_tolist, dctx); + return (result); +} + +static void +dumpcontext_destroy(struct dumpcontext *dctx) { + struct viewlistentry *vle; + struct zonelistentry *zle; + + vle = ISC_LIST_HEAD(dctx->viewlist); + while (vle != NULL) { + ISC_LIST_UNLINK(dctx->viewlist, vle, link); + zle = ISC_LIST_HEAD(vle->zonelist); + while (zle != NULL) { + ISC_LIST_UNLINK(vle->zonelist, zle, link); + dns_zone_detach(&zle->zone); + isc_mem_put(dctx->mctx, zle, sizeof *zle); + zle = ISC_LIST_HEAD(vle->zonelist); + } + dns_view_detach(&vle->view); + isc_mem_put(dctx->mctx, vle, sizeof *vle); + vle = ISC_LIST_HEAD(dctx->viewlist); + } + if (dctx->version != NULL) + dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE); + if (dctx->db != NULL) + dns_db_detach(&dctx->db); + if (dctx->cache != NULL) + dns_db_detach(&dctx->cache); + if (dctx->task != NULL) + isc_task_detach(&dctx->task); + if (dctx->fp != NULL) + (void)isc_stdio_close(dctx->fp); + if (dctx->mdctx != NULL) + dns_dumpctx_detach(&dctx->mdctx); + isc_mem_put(dctx->mctx, dctx, sizeof *dctx); +} + +static void +dumpdone(void *arg, isc_result_t result) { + struct dumpcontext *dctx = arg; + char buf[1024+32]; + const dns_master_style_t *style; + + if (result != ISC_R_SUCCESS) + goto cleanup; + if (dctx->mdctx != NULL) + dns_dumpctx_detach(&dctx->mdctx); + if (dctx->view == NULL) { + dctx->view = ISC_LIST_HEAD(dctx->viewlist); + if (dctx->view == NULL) + goto done; + INSIST(dctx->zone == NULL); + } else + goto resume; + nextview: + fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name); + resume: + if (dctx->zone == NULL && dctx->cache == NULL && dctx->dumpcache) { + style = &dns_master_style_cache; + /* start cache dump */ + if (dctx->view->view->cachedb != NULL) + dns_db_attach(dctx->view->view->cachedb, &dctx->cache); + if (dctx->cache != NULL) { + + fprintf(dctx->fp, ";\n; Cache dump of view '%s'\n;\n", + dctx->view->view->name); + result = dns_master_dumptostreaminc(dctx->mctx, + dctx->cache, NULL, + style, dctx->fp, + dctx->task, + dumpdone, dctx, + &dctx->mdctx); + if (result == DNS_R_CONTINUE) + return; + if (result == ISC_R_NOTIMPLEMENTED) + fprintf(dctx->fp, "; %s\n", + dns_result_totext(result)); + else if (result != ISC_R_SUCCESS) + goto cleanup; + } + } + if (dctx->cache != NULL) { + dns_adb_dump(dctx->view->view->adb, dctx->fp); + dns_db_detach(&dctx->cache); + } + if (dctx->dumpzones) { + style = &dns_master_style_full; + nextzone: + if (dctx->version != NULL) + dns_db_closeversion(dctx->db, &dctx->version, + ISC_FALSE); + if (dctx->db != NULL) + dns_db_detach(&dctx->db); + if (dctx->zone == NULL) + dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist); + else + dctx->zone = ISC_LIST_NEXT(dctx->zone, link); + if (dctx->zone != NULL) { + /* start zone dump */ + dns_zone_name(dctx->zone->zone, buf, sizeof(buf)); + fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf); + result = dns_zone_getdb(dctx->zone->zone, &dctx->db); + if (result != ISC_R_SUCCESS) { + fprintf(dctx->fp, "; %s\n", + dns_result_totext(result)); + goto nextzone; + } + dns_db_currentversion(dctx->db, &dctx->version); + result = dns_master_dumptostreaminc(dctx->mctx, + dctx->db, + dctx->version, + style, dctx->fp, + dctx->task, + dumpdone, dctx, + &dctx->mdctx); + if (result == DNS_R_CONTINUE) + return; + if (result == ISC_R_NOTIMPLEMENTED) { + fprintf(dctx->fp, "; %s\n", + dns_result_totext(result)); + result = ISC_R_SUCCESS; + goto nextzone; + } + if (result != ISC_R_SUCCESS) + goto cleanup; + } + } + if (dctx->view != NULL) + dctx->view = ISC_LIST_NEXT(dctx->view, link); + if (dctx->view != NULL) + goto nextview; + done: + fprintf(dctx->fp, "; Dump complete\n"); + result = isc_stdio_flush(dctx->fp); + if (result == ISC_R_SUCCESS) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "dumpdb complete"); + cleanup: + if (result != ISC_R_SUCCESS) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "dumpdb failed: %s", dns_result_totext(result)); + dumpcontext_destroy(dctx); +} + +isc_result_t +ns_server_dumpdb(ns_server_t *server, char *args) { + struct dumpcontext *dctx = NULL; + dns_view_t *view; + isc_result_t result; + char *ptr; + const char *sep; + + /* Skip the command name. */ + ptr = next_token(&args, " \t"); + if (ptr == NULL) + return (ISC_R_UNEXPECTEDEND); + + dctx = isc_mem_get(server->mctx, sizeof(*dctx)); + if (dctx == NULL) + return (ISC_R_NOMEMORY); + + dctx->mctx = server->mctx; + dctx->dumpcache = ISC_TRUE; + dctx->dumpzones = ISC_FALSE; + dctx->fp = NULL; + ISC_LIST_INIT(dctx->viewlist); + dctx->view = NULL; + dctx->zone = NULL; + dctx->cache = NULL; + dctx->mdctx = NULL; + dctx->db = NULL; + dctx->cache = NULL; + dctx->task = NULL; + dctx->version = NULL; + isc_task_attach(server->task, &dctx->task); + + CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp), + "could not open dump file", server->dumpfile); + + sep = (args == NULL) ? "" : ": "; + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "dumpdb started%s%s", sep, (args != NULL) ? args : ""); + + ptr = next_token(&args, " \t"); + if (ptr != NULL && strcmp(ptr, "-all") == 0) { + dctx->dumpzones = ISC_TRUE; + dctx->dumpcache = ISC_TRUE; + ptr = next_token(&args, " \t"); + } else if (ptr != NULL && strcmp(ptr, "-cache") == 0) { + dctx->dumpzones = ISC_FALSE; + dctx->dumpcache = ISC_TRUE; + ptr = next_token(&args, " \t"); + } else if (ptr != NULL && strcmp(ptr, "-zones") == 0) { + dctx->dumpzones = ISC_TRUE; + dctx->dumpcache = ISC_FALSE; + ptr = next_token(&args, " \t"); + } + + nextview: + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (ptr != NULL && strcmp(view->name, ptr) != 0) + continue; + CHECK(add_view_tolist(dctx, view)); + } + if (ptr != NULL) { + ptr = next_token(&args, " \t"); + if (ptr != NULL) + goto nextview; + } + dumpdone(dctx, ISC_R_SUCCESS); + return (ISC_R_SUCCESS); + + cleanup: + if (dctx != NULL) + dumpcontext_destroy(dctx); + return (result); +} + +isc_result_t +ns_server_dumprecursing(ns_server_t *server) { + FILE *fp = NULL; + isc_result_t result; + + CHECKMF(isc_stdio_open(server->recfile, "w", &fp), + "could not open dump file", server->recfile); + fprintf(fp,";\n; Recursing Queries\n;\n"); + ns_interfacemgr_dumprecursing(fp, server->interfacemgr); + fprintf(fp, "; Dump complete\n"); + + cleanup: + if (fp != NULL) + result = isc_stdio_close(fp); + if (result == ISC_R_SUCCESS) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "dumprecursing complete"); + else + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "dumprecursing failed: %s", + dns_result_totext(result)); + return (result); +} + +isc_result_t +ns_server_setdebuglevel(ns_server_t *server, char *args) { + char *ptr; + char *levelstr; + char *endp; + long newlevel; + + UNUSED(server); + + /* Skip the command name. */ + ptr = next_token(&args, " \t"); + if (ptr == NULL) + return (ISC_R_UNEXPECTEDEND); + + /* Look for the new level name. */ + levelstr = next_token(&args, " \t"); + if (levelstr == NULL) { + if (ns_g_debuglevel < 99) + ns_g_debuglevel++; + } else { + newlevel = strtol(levelstr, &endp, 10); + if (*endp != '\0' || newlevel < 0 || newlevel > 99) + return (ISC_R_RANGE); + ns_g_debuglevel = (unsigned int)newlevel; + } + isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "debug level is now %d", ns_g_debuglevel); + return (ISC_R_SUCCESS); +} + +isc_result_t +ns_server_validation(ns_server_t *server, char *args) { + char *ptr, *viewname; + dns_view_t *view; + isc_boolean_t changed = ISC_FALSE; + isc_result_t result; + isc_boolean_t enable; + + /* Skip the command name. */ + ptr = next_token(&args, " \t"); + if (ptr == NULL) + return (ISC_R_UNEXPECTEDEND); + + /* Find out what we are to do. */ + ptr = next_token(&args, " \t"); + if (ptr == NULL) + return (ISC_R_UNEXPECTEDEND); + + if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") || + !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true")) + enable = ISC_TRUE; + else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") || + !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false")) + enable = ISC_FALSE; + else + return (DNS_R_SYNTAX); + + /* Look for the view name. */ + viewname = next_token(&args, " \t"); + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (viewname != NULL && strcasecmp(viewname, view->name) != 0) + continue; + result = dns_view_flushcache(view); + if (result != ISC_R_SUCCESS) + goto out; + view->enablevalidation = enable; + changed = ISC_TRUE; + } + if (changed) + result = ISC_R_SUCCESS; + else + result = ISC_R_FAILURE; + out: + isc_task_endexclusive(server->task); + return (result); +} + +isc_result_t +ns_server_flushcache(ns_server_t *server, char *args) { + char *ptr, *viewname; + dns_view_t *view; + isc_boolean_t flushed; + isc_boolean_t found; + isc_result_t result; + + /* Skip the command name. */ + ptr = next_token(&args, " \t"); + if (ptr == NULL) + return (ISC_R_UNEXPECTEDEND); + + /* Look for the view name. */ + viewname = next_token(&args, " \t"); + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + flushed = ISC_TRUE; + found = ISC_FALSE; + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (viewname != NULL && strcasecmp(viewname, view->name) != 0) + continue; + found = ISC_TRUE; + result = dns_view_flushcache(view); + if (result != ISC_R_SUCCESS) { + flushed = ISC_FALSE; + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "flushing cache in view '%s' failed: %s", + view->name, isc_result_totext(result)); + } + } + if (flushed && found) { + if (viewname != NULL) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "flushing cache in view '%s' succeeded", + viewname); + else + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "flushing caches in all views succeeded"); + result = ISC_R_SUCCESS; + } else { + if (!found) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "flushing cache in view '%s' failed: " + "view not found", viewname); + result = ISC_R_NOTFOUND; + } else + result = ISC_R_FAILURE; + } + isc_task_endexclusive(server->task); + return (result); +} + +isc_result_t +ns_server_flushname(ns_server_t *server, char *args) { + char *ptr, *target, *viewname; + dns_view_t *view; + isc_boolean_t flushed; + isc_boolean_t found; + isc_result_t result; + isc_buffer_t b; + dns_fixedname_t fixed; + dns_name_t *name; + + /* Skip the command name. */ + ptr = next_token(&args, " \t"); + if (ptr == NULL) + return (ISC_R_UNEXPECTEDEND); + + /* Find the domain name to flush. */ + target = next_token(&args, " \t"); + if (target == NULL) + return (ISC_R_UNEXPECTEDEND); + + isc_buffer_init(&b, target, strlen(target)); + isc_buffer_add(&b, strlen(target)); + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL); + if (result != ISC_R_SUCCESS) + return (result); + + /* Look for the view name. */ + viewname = next_token(&args, " \t"); + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + flushed = ISC_TRUE; + found = ISC_FALSE; + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (viewname != NULL && strcasecmp(viewname, view->name) != 0) + continue; + found = ISC_TRUE; + result = dns_view_flushname(view, name); + if (result != ISC_R_SUCCESS) { + flushed = ISC_FALSE; + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "flushing name '%s' in cache view '%s' " + "failed: %s", target, view->name, + isc_result_totext(result)); + } + } + if (flushed && found) { + if (viewname != NULL) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "flushing name '%s' in cache view '%s' " + "succeeded", target, viewname); + else + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "flushing name '%s' in all cache views " + "succeeded", target); + result = ISC_R_SUCCESS; + } else { + if (!found) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "flushing name '%s' in cache view '%s' " + "failed: view not found", target, + viewname); + result = ISC_R_FAILURE; + } + isc_task_endexclusive(server->task); + return (result); +} + +isc_result_t +ns_server_status(ns_server_t *server, isc_buffer_t *text) { + int zonecount, xferrunning, xferdeferred, soaqueries; + unsigned int n; + const char *ob = "", *cb = "", *alt = ""; + + if (ns_g_server->version_set) { + ob = " ("; + cb = ")"; + if (ns_g_server->version == NULL) + alt = "version.bind/txt/ch disabled"; + else + alt = ns_g_server->version; + } + zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY); + xferrunning = dns_zonemgr_getcount(server->zonemgr, + DNS_ZONESTATE_XFERRUNNING); + xferdeferred = dns_zonemgr_getcount(server->zonemgr, + DNS_ZONESTATE_XFERDEFERRED); + soaqueries = dns_zonemgr_getcount(server->zonemgr, + DNS_ZONESTATE_SOAQUERY); + n = snprintf((char *)isc_buffer_used(text), + isc_buffer_availablelength(text), + "version: %s%s%s%s\n" + "number of zones: %u\n" + "debug level: %d\n" + "xfers running: %u\n" + "xfers deferred: %u\n" + "soa queries in progress: %u\n" + "query logging is %s\n" + "recursive clients: %d/%d/%d\n" + "tcp clients: %d/%d\n" + "server is up and running", + ns_g_version, ob, alt, cb, + zonecount, ns_g_debuglevel, xferrunning, xferdeferred, + soaqueries, server->log_queries ? "ON" : "OFF", + server->recursionquota.used, server->recursionquota.soft, + server->recursionquota.max, + server->tcpquota.used, server->tcpquota.max); + if (n >= isc_buffer_availablelength(text)) + return (ISC_R_NOSPACE); + isc_buffer_add(text, n); + return (ISC_R_SUCCESS); +} + +static isc_result_t +delete_keynames(dns_tsig_keyring_t *ring, char *target, + unsigned int *foundkeys) +{ + char namestr[DNS_NAME_FORMATSIZE]; + isc_result_t result; + dns_rbtnodechain_t chain; + dns_name_t foundname; + dns_fixedname_t fixedorigin; + dns_name_t *origin; + dns_rbtnode_t *node; + dns_tsigkey_t *tkey; + + dns_name_init(&foundname, NULL); + dns_fixedname_init(&fixedorigin); + origin = dns_fixedname_name(&fixedorigin); + + again: + dns_rbtnodechain_init(&chain, ring->mctx); + result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, + origin); + if (result == ISC_R_NOTFOUND) { + dns_rbtnodechain_invalidate(&chain); + return (ISC_R_SUCCESS); + } + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { + dns_rbtnodechain_invalidate(&chain); + return (result); + } + + for (;;) { + node = NULL; + dns_rbtnodechain_current(&chain, &foundname, origin, &node); + tkey = node->data; + + if (tkey != NULL) { + if (!tkey->generated) + goto nextkey; + + dns_name_format(&tkey->name, namestr, sizeof(namestr)); + if (strcmp(namestr, target) == 0) { + (*foundkeys)++; + dns_rbtnodechain_invalidate(&chain); + (void)dns_rbt_deletename(ring->keys, + &tkey->name, + ISC_FALSE); + goto again; + } + } + + nextkey: + result = dns_rbtnodechain_next(&chain, &foundname, origin); + if (result == ISC_R_NOMORE) + break; + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { + dns_rbtnodechain_invalidate(&chain); + return (result); + } + } + + return (ISC_R_SUCCESS); +} + +isc_result_t +ns_server_tsigdelete(ns_server_t *server, char *command, isc_buffer_t *text) { + isc_result_t result; + unsigned int n; + dns_view_t *view; + unsigned int foundkeys = 0; + char *target; + char *viewname; + + (void)next_token(&command, " \t"); /* skip command name */ + target = next_token(&command, " \t"); + if (target == NULL) + return (ISC_R_UNEXPECTEDEND); + viewname = next_token(&command, " \t"); + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) { + if (viewname == NULL || strcmp(view->name, viewname) == 0) { + RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_write); + result = delete_keynames(view->dynamickeys, target, + &foundkeys); + RWUNLOCK(&view->dynamickeys->lock, + isc_rwlocktype_write); + if (result != ISC_R_SUCCESS) { + isc_task_endexclusive(server->task); + return (result); + } + } + } + isc_task_endexclusive(server->task); + + n = snprintf((char *)isc_buffer_used(text), + isc_buffer_availablelength(text), + "%d tsig keys deleted.\n", foundkeys); + if (n >= isc_buffer_availablelength(text)) { + isc_task_endexclusive(server->task); + return (ISC_R_NOSPACE); + } + isc_buffer_add(text, n); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +list_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t *text, + unsigned int *foundkeys) +{ + char namestr[DNS_NAME_FORMATSIZE]; + char creatorstr[DNS_NAME_FORMATSIZE]; + isc_result_t result; + dns_rbtnodechain_t chain; + dns_name_t foundname; + dns_fixedname_t fixedorigin; + dns_name_t *origin; + dns_rbtnode_t *node; + dns_tsigkey_t *tkey; + unsigned int n; + const char *viewname; + + if (view != NULL) + viewname = view->name; + else + viewname = "(global)"; + + 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_NOTFOUND) { + dns_rbtnodechain_invalidate(&chain); + return (ISC_R_SUCCESS); + } + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { + dns_rbtnodechain_invalidate(&chain); + return (result); + } + + for (;;) { + node = NULL; + dns_rbtnodechain_current(&chain, &foundname, origin, &node); + tkey = node->data; + + if (tkey != NULL) { + (*foundkeys)++; + dns_name_format(&tkey->name, namestr, sizeof(namestr)); + if (tkey->generated) { + dns_name_format(tkey->creator, creatorstr, + sizeof(creatorstr)); + n = snprintf((char *)isc_buffer_used(text), + isc_buffer_availablelength(text), + "view \"%s\"; type \"dynamic\"; key \"%s\"; creator \"%s\";\n", + viewname, namestr, creatorstr); + } else { + n = snprintf((char *)isc_buffer_used(text), + isc_buffer_availablelength(text), + "view \"%s\"; type \"static\"; key \"%s\";\n", + viewname, namestr); + } + if (n >= isc_buffer_availablelength(text)) { + dns_rbtnodechain_invalidate(&chain); + return (ISC_R_NOSPACE); + } + isc_buffer_add(text, n); + } + result = dns_rbtnodechain_next(&chain, &foundname, origin); + if (result == ISC_R_NOMORE) + break; + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { + dns_rbtnodechain_invalidate(&chain); + return (result); + } + } + + return (ISC_R_SUCCESS); +} + +isc_result_t +ns_server_tsiglist(ns_server_t *server, isc_buffer_t *text) { + isc_result_t result; + unsigned int n; + dns_view_t *view; + unsigned int foundkeys = 0; + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) { + RWLOCK(&view->statickeys->lock, isc_rwlocktype_read); + result = list_keynames(view, view->statickeys, text, + &foundkeys); + RWUNLOCK(&view->statickeys->lock, isc_rwlocktype_read); + if (result != ISC_R_SUCCESS) { + isc_task_endexclusive(server->task); + return (result); + } + RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_read); + result = list_keynames(view, view->dynamickeys, text, + &foundkeys); + RWUNLOCK(&view->dynamickeys->lock, isc_rwlocktype_read); + if (result != ISC_R_SUCCESS) { + isc_task_endexclusive(server->task); + return (result); + } + } + isc_task_endexclusive(server->task); + + if (foundkeys == 0) { + n = snprintf((char *)isc_buffer_used(text), + isc_buffer_availablelength(text), + "no tsig keys found.\n"); + if (n >= isc_buffer_availablelength(text)) { + isc_task_endexclusive(server->task); + return (ISC_R_NOSPACE); + } + isc_buffer_add(text, n); + } + + return (ISC_R_SUCCESS); +} + +/* + * Act on a "freeze" or "thaw" command from the command channel. + */ +isc_result_t +ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args, + isc_buffer_t *text) +{ + isc_result_t result, tresult; + dns_zone_t *zone = NULL; + dns_zonetype_t type; + char classstr[DNS_RDATACLASS_FORMATSIZE]; + char zonename[DNS_NAME_FORMATSIZE]; + dns_view_t *view; + char *journal; + const char *vname, *sep; + isc_boolean_t frozen; + const char *msg = NULL; + + result = zone_from_args(server, args, &zone); + if (result != ISC_R_SUCCESS) + return (result); + if (zone == NULL) { + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + tresult = ISC_R_SUCCESS; + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) { + result = dns_view_freezezones(view, freeze); + if (result != ISC_R_SUCCESS && + tresult == ISC_R_SUCCESS) + tresult = result; + } + isc_task_endexclusive(server->task); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "%s all zones: %s", + freeze ? "freezing" : "thawing", + isc_result_totext(tresult)); + return (tresult); + } + type = dns_zone_gettype(zone); + if (type != dns_zone_master) { + dns_zone_detach(&zone); + return (ISC_R_NOTFOUND); + } + + frozen = dns_zone_getupdatedisabled(zone); + if (freeze) { + if (frozen) { + msg = "WARNING: The zone was already frozen.\n" + "Someone else may be editing it or " + "it may still be re-loading."; + result = DNS_R_FROZEN; + } + if (result == ISC_R_SUCCESS) { + result = dns_zone_flush(zone); + if (result != ISC_R_SUCCESS) + msg = "Flushing the zone updates to " + "disk failed."; + } + if (result == ISC_R_SUCCESS) { + journal = dns_zone_getjournal(zone); + if (journal != NULL) + (void)isc_file_remove(journal); + } + if (result == ISC_R_SUCCESS) + dns_zone_setupdatedisabled(zone, freeze); + } else { + if (frozen) { + result = dns_zone_loadandthaw(zone); + switch (result) { + case ISC_R_SUCCESS: + case DNS_R_UPTODATE: + msg = "The zone reload and thaw was " + "successful."; + result = ISC_R_SUCCESS; + break; + case DNS_R_CONTINUE: + msg = "A zone reload and thaw was started.\n" + "Check the logs to see the result."; + result = ISC_R_SUCCESS; + break; + } + } + } + + if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text)) + isc_buffer_putmem(text, (const unsigned char *)msg, + strlen(msg) + 1); + + view = dns_zone_getview(zone); + if (strcmp(view->name, "_bind") == 0 || + strcmp(view->name, "_default") == 0) + { + vname = ""; + sep = ""; + } else { + vname = view->name; + sep = " "; + } + dns_rdataclass_format(dns_zone_getclass(zone), classstr, + sizeof(classstr)); + dns_name_format(dns_zone_getorigin(zone), + zonename, sizeof(zonename)); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "%s zone '%s/%s'%s%s: %s", + freeze ? "freezing" : "thawing", + zonename, classstr, sep, vname, + isc_result_totext(result)); + dns_zone_detach(&zone); + return (result); +} + +#ifdef HAVE_LIBSCF +/* + * This function adds a message for rndc to echo if named + * is managed by smf and is also running chroot. + */ +isc_result_t +ns_smf_add_message(isc_buffer_t *text) { + unsigned int n; + + n = snprintf((char *)isc_buffer_used(text), + isc_buffer_availablelength(text), + "use svcadm(1M) to manage named"); + if (n >= isc_buffer_availablelength(text)) + return (ISC_R_NOSPACE); + isc_buffer_add(text, n); + return (ISC_R_SUCCESS); +} +#endif /* HAVE_LIBSCF */ diff --git a/contrib/bind-9.5.2/bin/named/sortlist.c b/contrib/bind-9.5.2/bin/named/sortlist.c new file mode 100644 index 0000000000..daefa0772e --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/sortlist.c @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * 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: sortlist.c,v 1.17 2007/09/14 01:46:05 marka Exp $ */ + +/*! \file */ + +#include + +#include +#include + +#include +#include + +#include +#include +#include + +ns_sortlisttype_t +ns_sortlist_setup(dns_acl_t *acl, isc_netaddr_t *clientaddr, + const void **argp) +{ + unsigned int i; + + if (acl == NULL) + goto dont_sort; + + for (i = 0; i < acl->length; i++) { + /* + * 'e' refers to the current 'top level statement' + * in the sortlist (see ARM). + */ + dns_aclelement_t *e = &acl->elements[i]; + dns_aclelement_t *try_elt; + dns_aclelement_t *order_elt = NULL; + const dns_aclelement_t *matched_elt = NULL; + + if (e->type == dns_aclelementtype_nestedacl) { + dns_acl_t *inner = e->nestedacl; + + if (inner->length == 0) + try_elt = e; + else if (inner->length > 2) + goto dont_sort; + else if (inner->elements[0].negative) + goto dont_sort; + else { + try_elt = &inner->elements[0]; + if (inner->length == 2) + order_elt = &inner->elements[1]; + } + } else { + /* + * BIND 8 allows bare elements at the top level + * as an undocumented feature. + */ + try_elt = e; + } + + if (dns_aclelement_match(clientaddr, NULL, try_elt, + &ns_g_server->aclenv, + &matched_elt)) { + if (order_elt != NULL) { + if (order_elt->type == + dns_aclelementtype_nestedacl) { + *argp = order_elt->nestedacl; + return (NS_SORTLISTTYPE_2ELEMENT); + } else if (order_elt->type == + dns_aclelementtype_localhost && + ns_g_server->aclenv.localhost != NULL) { + *argp = ns_g_server->aclenv.localhost; + return (NS_SORTLISTTYPE_2ELEMENT); + } else if (order_elt->type == + dns_aclelementtype_localnets && + ns_g_server->aclenv.localnets != NULL) { + *argp = ns_g_server->aclenv.localnets; + return (NS_SORTLISTTYPE_2ELEMENT); + } else { + /* + * BIND 8 allows a bare IP prefix as + * the 2nd element of a 2-element + * sortlist statement. + */ + *argp = order_elt; + return (NS_SORTLISTTYPE_1ELEMENT); + } + } else { + INSIST(matched_elt != NULL); + *argp = matched_elt; + return (NS_SORTLISTTYPE_1ELEMENT); + } + } + } + + /* No match; don't sort. */ + dont_sort: + *argp = NULL; + return (NS_SORTLISTTYPE_NONE); +} + +int +ns_sortlist_addrorder2(const isc_netaddr_t *addr, const void *arg) { + const dns_acl_t *sortacl = (const dns_acl_t *) arg; + int match; + + (void)dns_acl_match(addr, NULL, sortacl, + &ns_g_server->aclenv, + &match, NULL); + if (match > 0) + return (match); + else if (match < 0) + return (INT_MAX - (-match)); + else + return (INT_MAX / 2); +} + +int +ns_sortlist_addrorder1(const isc_netaddr_t *addr, const void *arg) { + const dns_aclelement_t *matchelt = (const dns_aclelement_t *) arg; + if (dns_aclelement_match(addr, NULL, matchelt, + &ns_g_server->aclenv, + NULL)) { + return (0); + } else { + return (INT_MAX); + } +} + +void +ns_sortlist_byaddrsetup(dns_acl_t *sortlist_acl, isc_netaddr_t *client_addr, + dns_addressorderfunc_t *orderp, + const void **argp) +{ + ns_sortlisttype_t sortlisttype; + + sortlisttype = ns_sortlist_setup(sortlist_acl, client_addr, argp); + + switch (sortlisttype) { + case NS_SORTLISTTYPE_1ELEMENT: + *orderp = ns_sortlist_addrorder1; + break; + case NS_SORTLISTTYPE_2ELEMENT: + *orderp = ns_sortlist_addrorder2; + break; + case NS_SORTLISTTYPE_NONE: + *orderp = NULL; + break; + default: + UNEXPECTED_ERROR(__FILE__, __LINE__, + "unexpected return from ns_sortlist_setup(): " + "%d", sortlisttype); + break; + } +} + diff --git a/contrib/bind-9.5.2/bin/named/statschannel.c b/contrib/bind-9.5.2/bin/named/statschannel.c new file mode 100644 index 0000000000..8d65935ffe --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/statschannel.c @@ -0,0 +1,1355 @@ +/* + * Copyright (C) 2008, 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: statschannel.c,v 1.2.2.19 2009/02/17 03:47:27 marka Exp $ */ + +/*! \file */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "bind9.xsl.h" + +struct ns_statschannel { + /* Unlocked */ + isc_httpdmgr_t *httpdmgr; + isc_sockaddr_t address; + isc_mem_t *mctx; + + /* + * Locked by channel lock: can be referenced and modified by both + * the server task and the channel task. + */ + isc_mutex_t lock; + dns_acl_t *acl; + + /* Locked by server task */ + ISC_LINK(struct ns_statschannel) link; +}; + +typedef enum { statsformat_file, statsformat_xml } statsformat_t; + +typedef struct +stats_dumparg { + statsformat_t type; + void *arg; /* type dependent argument */ + int ncounters; /* used for general statistics */ + int *counterindices; /* used for general statistics */ + isc_uint64_t *countervalues; /* used for general statistics */ +} stats_dumparg_t; + +static isc_once_t once = ISC_ONCE_INIT; + +/*% + * Statistics descriptions. These could be statistically initialized at + * compile time, but we configure them run time in the init_desc() function + * below so that they'll be less susceptible to counter name changes. + */ +static const char *nsstats_desc[dns_nsstatscounter_max]; +static const char *resstats_desc[dns_resstatscounter_max]; +static const char *zonestats_desc[dns_zonestatscounter_max]; +static const char *sockstats_desc[isc_sockstatscounter_max]; +#ifdef HAVE_LIBXML2 +static const char *nsstats_xmldesc[dns_nsstatscounter_max]; +static const char *resstats_xmldesc[dns_resstatscounter_max]; +static const char *zonestats_xmldesc[dns_zonestatscounter_max]; +static const char *sockstats_xmldesc[isc_sockstatscounter_max]; +#else +#define nsstats_xmldesc NULL +#define resstats_xmldesc NULL +#define zonestats_xmldesc NULL +#define sockstats_xmldesc NULL +#endif /* HAVE_LIBXML2 */ + +/*% + * Mapping arrays to represent statistics counters in the order of our + * preference, regardless of the order of counter indices. For example, + * nsstats_desc[nsstats_index[0]] will be the description that is shown first. + */ +static int nsstats_index[dns_nsstatscounter_max]; +static int resstats_index[dns_resstatscounter_max]; +static int zonestats_index[dns_zonestatscounter_max]; +static int sockstats_index[isc_sockstatscounter_max]; + +static inline void +set_desc(int counter, int maxcounter, const char *fdesc, const char **fdescs, + const char *xdesc, const char **xdescs) +{ + REQUIRE(counter < maxcounter); + REQUIRE(fdescs[counter] == NULL); +#ifdef HAVE_LIBXML2 + REQUIRE(xdescs[counter] == NULL); +#endif + + fdescs[counter] = fdesc; +#ifdef HAVE_LIBXML2 + xdescs[counter] = xdesc; +#else + UNUSED(xdesc); + UNUSED(xdescs); +#endif +} + +static void +init_desc(void) { + int i; + + /* Initialize name server statistics */ + memset((void *)nsstats_desc, 0, + dns_nsstatscounter_max * sizeof(nsstats_desc[0])); +#ifdef HAVE_LIBXML2 + memset((void *)nsstats_xmldesc, 0, + dns_nsstatscounter_max * sizeof(nsstats_xmldesc[0])); +#endif + +#define SET_NSSTATDESC(counterid, desc, xmldesc) \ + do { \ + set_desc(dns_nsstatscounter_ ## counterid, \ + dns_nsstatscounter_max, \ + desc, nsstats_desc, xmldesc, nsstats_xmldesc); \ + nsstats_index[i++] = dns_nsstatscounter_ ## counterid; \ + } while (0) + + i = 0; + SET_NSSTATDESC(requestv4, "IPv4 requests received", "Requestv4"); + SET_NSSTATDESC(requestv6, "IPv6 requests received", "Requestv6"); + SET_NSSTATDESC(edns0in, "requests with EDNS(0) received", "ReqEdns0"); + SET_NSSTATDESC(badednsver, + "requests with unsupported EDNS version received", + "ReqBadEDNSVer"); + SET_NSSTATDESC(tsigin, "requests with TSIG received", "ReqTSIG"); + SET_NSSTATDESC(sig0in, "requests with SIG(0) received", "ReqSIG0"); + SET_NSSTATDESC(invalidsig, "requests with invalid signature", + "ReqBadSIG"); + SET_NSSTATDESC(tcp, "TCP requests received", "ReqTCP"); + SET_NSSTATDESC(authrej, "auth queries rejected", "AuthQryRej"); + SET_NSSTATDESC(recurserej, "recursive queries rejected", "RecQryRej"); + SET_NSSTATDESC(xfrrej, "transfer requests rejected", "XfrRej"); + SET_NSSTATDESC(updaterej, "update requests rejected", "UpdateRej"); + SET_NSSTATDESC(response, "responses sent", "Response"); + SET_NSSTATDESC(truncatedresp, "truncated responses sent", + "TruncatedResp"); + SET_NSSTATDESC(edns0out, "responses with EDNS(0) sent", "RespEDNS0"); + SET_NSSTATDESC(tsigout, "responses with TSIG sent", "RespTSIG"); + SET_NSSTATDESC(sig0out, "responses with SIG(0) sent", "RespSIG0"); + SET_NSSTATDESC(success, "queries resulted in successful answer", + "QrySuccess"); + SET_NSSTATDESC(authans, "queries resulted in authoritative answer", + "QryAuthAns"); + SET_NSSTATDESC(nonauthans, + "queries resulted in non authoritative answer", + "QryNoauthAns"); + SET_NSSTATDESC(referral, "queries resulted in referral answer", + "QryReferral"); + SET_NSSTATDESC(nxrrset, "queries resulted in nxrrset", "QryNxrrset"); + SET_NSSTATDESC(servfail, "queries resulted in SERVFAIL", "QrySERVFAIL"); + SET_NSSTATDESC(formerr, "queries resulted in FORMERR", "QryFORMERR"); + SET_NSSTATDESC(nxdomain, "queries resulted in NXDOMAIN", "QryNXDOMAIN"); + SET_NSSTATDESC(recursion, "queries caused recursion","QryRecursion"); + SET_NSSTATDESC(duplicate, "duplicate queries received", "QryDuplicate"); + SET_NSSTATDESC(dropped, "queries dropped", "QryDropped"); + SET_NSSTATDESC(failure, "other query failures", "QryFailure"); + SET_NSSTATDESC(xfrdone, "requested transfers completed", "XfrReqDone"); + SET_NSSTATDESC(updatereqfwd, "update requests forwarded", + "UpdateReqFwd"); + SET_NSSTATDESC(updaterespfwd, "update responses forwarded", + "UpdateRespFwd"); + SET_NSSTATDESC(updatefwdfail, "update forward failed", "UpdateFwdFail"); + SET_NSSTATDESC(updatedone, "updates completed", "UpdateDone"); + SET_NSSTATDESC(updatefail, "updates failed", "UpdateFail"); + SET_NSSTATDESC(updatebadprereq, + "updates rejected due to prerequisite failure", + "UpdateBadPrereq"); + INSIST(i == dns_nsstatscounter_max); + + /* Initialize resolver statistics */ + memset((void *)resstats_desc, 0, + dns_resstatscounter_max * sizeof(resstats_desc[0])); +#ifdef HAVE_LIBXML2 + memset((void *)resstats_xmldesc, 0, + dns_resstatscounter_max * sizeof(resstats_xmldesc[0])); +#endif + +#define SET_RESSTATDESC(counterid, desc, xmldesc) \ + do { \ + set_desc(dns_resstatscounter_ ## counterid, \ + dns_resstatscounter_max, \ + desc, resstats_desc, xmldesc, resstats_xmldesc); \ + resstats_index[i++] = dns_resstatscounter_ ## counterid; \ + } while (0) + + i = 0; + SET_RESSTATDESC(queryv4, "IPv4 queries sent", "Queryv4"); + SET_RESSTATDESC(queryv6, "IPv6 queries sent", "Queryv6"); + SET_RESSTATDESC(responsev4, "IPv4 responses received", "Responsev4"); + SET_RESSTATDESC(responsev6, "IPv6 responses received", "Responsev6"); + SET_RESSTATDESC(nxdomain, "NXDOMAIN received", "NXDOMAIN"); + SET_RESSTATDESC(servfail, "SERVFAIL received", "SERVFAIL"); + SET_RESSTATDESC(formerr, "FORMERR received", "FORMERR"); + SET_RESSTATDESC(othererror, "other errors received", "OtherError"); + SET_RESSTATDESC(edns0fail, "EDNS(0) query failures", "EDNS0Fail"); + SET_RESSTATDESC(mismatch, "mismatch responses received", "Mismatch"); + SET_RESSTATDESC(truncated, "truncated responses received", "Truncated"); + SET_RESSTATDESC(lame, "lame delegations received", "Lame"); + SET_RESSTATDESC(retry, "query retries", "Retry"); + SET_RESSTATDESC(dispabort, "queries aborted due to quota", + "QueryAbort"); + SET_RESSTATDESC(dispsockfail, "failures in opening query sockets", + "QuerySockFail"); + SET_RESSTATDESC(querytimeout, "query timeouts", "QueryTimeout"); + SET_RESSTATDESC(gluefetchv4, "IPv4 NS address fetches", "GlueFetchv4"); + SET_RESSTATDESC(gluefetchv6, "IPv6 NS address fetches", "GlueFetchv6"); + SET_RESSTATDESC(gluefetchv4fail, "IPv4 NS address fetch failed", + "GlueFetchv4Fail"); + SET_RESSTATDESC(gluefetchv6fail, "IPv6 NS address fetch failed", + "GlueFetchv6Fail"); + SET_RESSTATDESC(val, "DNSSEC validation attempted", "ValAttempt"); + SET_RESSTATDESC(valsuccess, "DNSSEC validation succeeded", "ValOk"); + SET_RESSTATDESC(valnegsuccess, "DNSSEC NX validation succeeded", + "ValNegOk"); + SET_RESSTATDESC(valfail, "DNSSEC validation failed", "ValFail"); + SET_RESSTATDESC(queryrtt0, "queries with RTT < " + DNS_RESOLVER_QRYRTTCLASS0STR "ms", + "QryRTT" DNS_RESOLVER_QRYRTTCLASS0STR); + SET_RESSTATDESC(queryrtt1, "queries with RTT " + DNS_RESOLVER_QRYRTTCLASS0STR "-" + DNS_RESOLVER_QRYRTTCLASS1STR "ms", + "QryRTT" DNS_RESOLVER_QRYRTTCLASS1STR); + SET_RESSTATDESC(queryrtt2, "queries with RTT " + DNS_RESOLVER_QRYRTTCLASS1STR "-" + DNS_RESOLVER_QRYRTTCLASS2STR "ms", + "QryRTT" DNS_RESOLVER_QRYRTTCLASS2STR); + SET_RESSTATDESC(queryrtt3, "queries with RTT " + DNS_RESOLVER_QRYRTTCLASS2STR "-" + DNS_RESOLVER_QRYRTTCLASS3STR "ms", + "QryRTT" DNS_RESOLVER_QRYRTTCLASS3STR); + SET_RESSTATDESC(queryrtt4, "queries with RTT " + DNS_RESOLVER_QRYRTTCLASS3STR "-" + DNS_RESOLVER_QRYRTTCLASS4STR "ms", + "QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR); + SET_RESSTATDESC(queryrtt5, "queries with RTT > " + DNS_RESOLVER_QRYRTTCLASS4STR "ms", + "QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR "+"); + INSIST(i == dns_resstatscounter_max); + + /* Initialize zone statistics */ + memset((void *)zonestats_desc, 0, + dns_zonestatscounter_max * sizeof(zonestats_desc[0])); +#ifdef HAVE_LIBXML2 + memset((void *)zonestats_xmldesc, 0, + dns_zonestatscounter_max * sizeof(zonestats_xmldesc[0])); +#endif + +#define SET_ZONESTATDESC(counterid, desc, xmldesc) \ + do { \ + set_desc(dns_zonestatscounter_ ## counterid, \ + dns_zonestatscounter_max, \ + desc, zonestats_desc, xmldesc, zonestats_xmldesc); \ + zonestats_index[i++] = dns_zonestatscounter_ ## counterid; \ + } while (0) + + i = 0; + SET_ZONESTATDESC(notifyoutv4, "IPv4 notifies sent", "NotifyOutv4"); + SET_ZONESTATDESC(notifyoutv6, "IPv6 notifies sent", "NotifyOutv6"); + SET_ZONESTATDESC(notifyinv4, "IPv4 notifies received", "NotifyInv4"); + SET_ZONESTATDESC(notifyinv6, "IPv6 notifies received", "NotifyInv6"); + SET_ZONESTATDESC(notifyrej, "notifies rejected", "NotifyRej"); + SET_ZONESTATDESC(soaoutv4, "IPv4 SOA queries sent", "SOAOutv4"); + SET_ZONESTATDESC(soaoutv6, "IPv6 SOA queries sent", "SOAOutv6"); + SET_ZONESTATDESC(axfrreqv4, "IPv4 AXFR requested", "AXFRReqv4"); + SET_ZONESTATDESC(axfrreqv6, "IPv6 AXFR requested", "AXFRReqv6"); + SET_ZONESTATDESC(ixfrreqv4, "IPv4 IXFR requested", "IXFRReqv4"); + SET_ZONESTATDESC(ixfrreqv6, "IPv6 IXFR requested", "IXFRReqv6"); + SET_ZONESTATDESC(xfrsuccess, "transfer requests succeeded","XfrSuccess"); + SET_ZONESTATDESC(xfrfail, "transfer requests failed", "XfrFail"); + INSIST(i == dns_zonestatscounter_max); + + /* Initialize socket statistics */ + memset((void *)sockstats_desc, 0, + isc_sockstatscounter_max * sizeof(sockstats_desc[0])); +#ifdef HAVE_LIBXML2 + memset((void *)sockstats_xmldesc, 0, + isc_sockstatscounter_max * sizeof(sockstats_xmldesc[0])); +#endif + +#define SET_SOCKSTATDESC(counterid, desc, xmldesc) \ + do { \ + set_desc(isc_sockstatscounter_ ## counterid, \ + isc_sockstatscounter_max, \ + desc, sockstats_desc, xmldesc, sockstats_xmldesc); \ + sockstats_index[i++] = isc_sockstatscounter_ ## counterid; \ + } while (0) + + i = 0; + SET_SOCKSTATDESC(udp4open, "UDP/IPv4 sockets opened", "UDP4Open"); + SET_SOCKSTATDESC(udp6open, "UDP/IPv6 sockets opened", "UDP6Open"); + SET_SOCKSTATDESC(tcp4open, "TCP/IPv4 sockets opened", "TCP4Open"); + SET_SOCKSTATDESC(tcp6open, "TCP/IPv6 sockets opened", "TCP6Open"); + SET_SOCKSTATDESC(unixopen, "Unix domain sockets opened", "UnixOpen"); + SET_SOCKSTATDESC(udp4openfail, "UDP/IPv4 socket open failures", + "UDP4OpenFail"); + SET_SOCKSTATDESC(udp6openfail, "UDP/IPv6 socket open failures", + "UDP6OpenFail"); + SET_SOCKSTATDESC(tcp4openfail, "TCP/IPv4 socket open failures", + "TCP4OpenFail"); + SET_SOCKSTATDESC(tcp6openfail, "TCP/IPv6 socket open failures", + "TCP6OpenFail"); + SET_SOCKSTATDESC(unixopenfail, "Unix domain socket open failures", + "UnixOpenFail"); + SET_SOCKSTATDESC(udp4close, "UDP/IPv4 sockets closed", "UDP4Close"); + SET_SOCKSTATDESC(udp6close, "UDP/IPv6 sockets closed", "UDP6Close"); + SET_SOCKSTATDESC(tcp4close, "TCP/IPv4 sockets closed", "TCP4Close"); + SET_SOCKSTATDESC(tcp6close, "TCP/IPv6 sockets closed", "TCP6Close"); + SET_SOCKSTATDESC(unixclose, "Unix domain sockets closed", "UnixClose"); + SET_SOCKSTATDESC(fdwatchclose, "FDwatch sockets closed", + "FDWatchClose"); + SET_SOCKSTATDESC(udp4bindfail, "UDP/IPv4 socket bind failures", + "UDP4BindFail"); + SET_SOCKSTATDESC(udp6bindfail, "UDP/IPv6 socket bind failures", + "UDP6BindFail"); + SET_SOCKSTATDESC(tcp4bindfail, "TCP/IPv4 socket bind failures", + "TCP4BindFail"); + SET_SOCKSTATDESC(tcp6bindfail, "TCP/IPv6 socket bind failures", + "TCP6BindFail"); + SET_SOCKSTATDESC(unixbindfail, "Unix domain socket bind failures", + "UnixBindFail"); + SET_SOCKSTATDESC(fdwatchbindfail, "FDwatch socket bind failures", + "FdwatchBindFail"); + SET_SOCKSTATDESC(udp4connectfail, "UDP/IPv4 socket connect failures", + "UDP4ConnFail"); + SET_SOCKSTATDESC(udp6connectfail, "UDP/IPv6 socket connect failures", + "UDP6ConnFail"); + SET_SOCKSTATDESC(tcp4connectfail, "TCP/IPv4 socket connect failures", + "TCP4ConnFail"); + SET_SOCKSTATDESC(tcp6connectfail, "TCP/IPv6 socket connect failures", + "TCP6ConnFail"); + SET_SOCKSTATDESC(unixconnectfail, "Unix domain socket connect failures", + "UnixConnFail"); + SET_SOCKSTATDESC(fdwatchconnectfail, "FDwatch socket connect failures", + "FDwatchConnFail"); + SET_SOCKSTATDESC(udp4connect, "UDP/IPv4 connections established", + "UDP4Conn"); + SET_SOCKSTATDESC(udp6connect, "UDP/IPv6 connections established", + "UDP6Conn"); + SET_SOCKSTATDESC(tcp4connect, "TCP/IPv4 connections established", + "TCP4Conn"); + SET_SOCKSTATDESC(tcp6connect, "TCP/IPv6 connections established", + "TCP6Conn"); + SET_SOCKSTATDESC(unixconnect, "Unix domain connections established", + "UnixConn"); + SET_SOCKSTATDESC(fdwatchconnect, + "FDwatch domain connections established", + "FDwatchConn"); + SET_SOCKSTATDESC(tcp4acceptfail, "TCP/IPv4 connection accept failures", + "TCP4AcceptFail"); + SET_SOCKSTATDESC(tcp6acceptfail, "TCP/IPv6 connection accept failures", + "TCP6AcceptFail"); + SET_SOCKSTATDESC(unixacceptfail, + "Unix domain connection accept failures", + "UnixAcceptFail"); + SET_SOCKSTATDESC(tcp4accept, "TCP/IPv4 connections accepted", + "TCP4Accept"); + SET_SOCKSTATDESC(tcp6accept, "TCP/IPv6 connections accepted", + "TCP6Accept"); + SET_SOCKSTATDESC(unixaccept, "Unix domain connections accepted", + "UnixAccept"); + SET_SOCKSTATDESC(udp4sendfail, "UDP/IPv4 send errors", "UDP4SendErr"); + SET_SOCKSTATDESC(udp6sendfail, "UDP/IPv6 send errors", "UDP6SendErr"); + SET_SOCKSTATDESC(tcp4sendfail, "TCP/IPv4 send errors", "TCP4SendErr"); + SET_SOCKSTATDESC(tcp6sendfail, "TCP/IPv6 send errors", "TCP6SendErr"); + SET_SOCKSTATDESC(unixsendfail, "Unix domain send errors", + "UnixSendErr"); + SET_SOCKSTATDESC(fdwatchsendfail, "FDwatch send errors", + "FDwatchSendErr"); + SET_SOCKSTATDESC(udp4recvfail, "UDP/IPv4 recv errors", "UDP4RecvErr"); + SET_SOCKSTATDESC(udp6recvfail, "UDP/IPv6 recv errors", "UDP6RecvErr"); + SET_SOCKSTATDESC(tcp4recvfail, "TCP/IPv4 recv errors", "TCP4RecvErr"); + SET_SOCKSTATDESC(tcp6recvfail, "TCP/IPv6 recv errors", "TCP6RecvErr"); + SET_SOCKSTATDESC(unixrecvfail, "Unix domain recv errors", + "UnixRecvErr"); + SET_SOCKSTATDESC(fdwatchrecvfail, "FDwatch recv errors", + "FDwatchRecvErr"); + INSIST(i == isc_sockstatscounter_max); + + /* Sanity check */ + for (i = 0; i < dns_nsstatscounter_max; i++) + INSIST(nsstats_desc[i] != NULL); + for (i = 0; i < dns_resstatscounter_max; i++) + INSIST(resstats_desc[i] != NULL); + for (i = 0; i < dns_zonestatscounter_max; i++) + INSIST(zonestats_desc[i] != NULL); + for (i = 0; i < isc_sockstatscounter_max; i++) + INSIST(sockstats_desc[i] != NULL); +#ifdef HAVE_LIBXML2 + for (i = 0; i < dns_nsstatscounter_max; i++) + INSIST(nsstats_xmldesc[i] != NULL); + for (i = 0; i < dns_resstatscounter_max; i++) + INSIST(resstats_xmldesc[i] != NULL); + for (i = 0; i < dns_zonestatscounter_max; i++) + INSIST(zonestats_xmldesc[i] != NULL); + for (i = 0; i < isc_sockstatscounter_max; i++) + INSIST(sockstats_xmldesc[i] != NULL); +#endif +} + +/*% + * Dump callback functions. + */ +static void +generalstat_dump(isc_statscounter_t counter, isc_uint64_t val, void *arg) { + stats_dumparg_t *dumparg = arg; + + REQUIRE(counter < dumparg->ncounters); + dumparg->countervalues[counter] = val; +} + +static void +dump_counters(isc_stats_t *stats, statsformat_t type, void *arg, + const char *category, const char **desc, int ncounters, + int *indices, isc_uint64_t *values, int options) +{ + int i, index; + isc_uint64_t value; + stats_dumparg_t dumparg; + FILE *fp; +#ifdef HAVE_LIBXML2 + xmlTextWriterPtr writer; +#endif + +#ifndef HAVE_LIBXML2 + UNUSED(category); +#endif + + dumparg.type = type; + dumparg.ncounters = ncounters; + dumparg.counterindices = indices; + dumparg.countervalues = values; + + memset(values, 0, sizeof(values[0]) * ncounters); + isc_stats_dump(stats, generalstat_dump, &dumparg, options); + + for (i = 0; i < ncounters; i++) { + index = indices[i]; + value = values[index]; + + if (value == 0 && (options & ISC_STATSDUMP_VERBOSE) == 0) + continue; + + switch (dumparg.type) { + case statsformat_file: + fp = arg; + fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", + value, desc[index]); + break; + case statsformat_xml: +#ifdef HAVE_LIBXML2 + writer = arg; + + if (category != NULL) { + xmlTextWriterStartElement(writer, + ISC_XMLCHAR + category); + xmlTextWriterStartElement(writer, + ISC_XMLCHAR "name"); + xmlTextWriterWriteString(writer, ISC_XMLCHAR + desc[index]); + xmlTextWriterEndElement(writer); /* name */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR + "counter"); + } else { + xmlTextWriterStartElement(writer, ISC_XMLCHAR + desc[index]); + } + xmlTextWriterWriteFormatString(writer, + "%" ISC_PRINT_QUADFORMAT + "u", value); + xmlTextWriterEndElement(writer); /* counter */ + if (category != NULL) + xmlTextWriterEndElement(writer); /* category */ +#endif + break; + } + } +} + +static void +rdtypestat_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) { + char typebuf[64]; + const char *typestr; + stats_dumparg_t *dumparg = arg; + FILE *fp; +#ifdef HAVE_LIBXML2 + xmlTextWriterPtr writer; +#endif + + if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_OTHERTYPE) + == 0) { + dns_rdatatype_format(DNS_RDATASTATSTYPE_BASE(type), typebuf, + sizeof(typebuf)); + typestr = typebuf; + } else + typestr = "Others"; + + switch (dumparg->type) { + case statsformat_file: + fp = dumparg->arg; + fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", val, typestr); + break; + case statsformat_xml: +#ifdef HAVE_LIBXML2 + writer = dumparg->arg; + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "rdtype"); + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"); + xmlTextWriterWriteString(writer, ISC_XMLCHAR typestr); + xmlTextWriterEndElement(writer); /* name */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"); + xmlTextWriterWriteFormatString(writer, + "%" ISC_PRINT_QUADFORMAT "u", + val); + xmlTextWriterEndElement(writer); /* counter */ + + xmlTextWriterEndElement(writer); /* rdtype */ +#endif + break; + } +} + +static void +rdatasetstats_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) { + stats_dumparg_t *dumparg = arg; + FILE *fp; + char typebuf[64]; + const char *typestr; + isc_boolean_t nxrrset = ISC_FALSE; +#ifdef HAVE_LIBXML2 + xmlTextWriterPtr writer; +#endif + + if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_NXDOMAIN) + != 0) { + typestr = "NXDOMAIN"; + } else if ((DNS_RDATASTATSTYPE_ATTR(type) & + DNS_RDATASTATSTYPE_ATTR_OTHERTYPE) != 0) { + typestr = "Others"; + } else { + dns_rdatatype_format(DNS_RDATASTATSTYPE_BASE(type), typebuf, + sizeof(typebuf)); + typestr = typebuf; + } + + if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_NXRRSET) + != 0) + nxrrset = ISC_TRUE; + + switch (dumparg->type) { + case statsformat_file: + fp = dumparg->arg; + fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s%s\n", val, + nxrrset ? "!" : "", typestr); + break; + case statsformat_xml: +#ifdef HAVE_LIBXML2 + writer = dumparg->arg; + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "rrset"); + xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"); + xmlTextWriterWriteFormatString(writer, "%s%s", + nxrrset ? "!" : "", typestr); + xmlTextWriterEndElement(writer); /* name */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"); + xmlTextWriterWriteFormatString(writer, + "%" ISC_PRINT_QUADFORMAT "u", + val); + xmlTextWriterEndElement(writer); /* counter */ + + xmlTextWriterEndElement(writer); /* rrset */ +#endif + break; + } +} + +static void +opcodestat_dump(dns_opcode_t code, isc_uint64_t val, void *arg) { + FILE *fp = arg; + isc_buffer_t b; + char codebuf[64]; + stats_dumparg_t *dumparg = arg; +#ifdef HAVE_LIBXML2 + xmlTextWriterPtr writer; +#endif + + isc_buffer_init(&b, codebuf, sizeof(codebuf) - 1); + dns_opcode_totext(code, &b); + codebuf[isc_buffer_usedlength(&b)] = '\0'; + + switch (dumparg->type) { + case statsformat_file: + fp = dumparg->arg; + fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", val, codebuf); + break; + case statsformat_xml: +#ifdef HAVE_LIBXML2 + writer = dumparg->arg; + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "opcode"); + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"); + xmlTextWriterWriteString(writer, ISC_XMLCHAR codebuf); + xmlTextWriterEndElement(writer); /* name */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"); + xmlTextWriterWriteFormatString(writer, + "%" ISC_PRINT_QUADFORMAT "u", + val); + xmlTextWriterEndElement(writer); /* counter */ + + xmlTextWriterEndElement(writer); /* opcode */ +#endif + break; + } +} + +#ifdef HAVE_LIBXML2 + +/* XXXMLG below here sucks. */ + +#define TRY(a) do { result = (a); INSIST(result == ISC_R_SUCCESS); } while(0); +#define TRY0(a) do { xmlrc = (a); INSIST(xmlrc >= 0); } while(0); + +static isc_result_t +zone_xmlrender(dns_zone_t *zone, void *arg) { + char buf[1024 + 32]; /* sufficiently large for zone name and class */ + dns_rdataclass_t rdclass; + isc_uint32_t serial; + xmlTextWriterPtr writer = arg; + isc_stats_t *zonestats; + isc_uint64_t nsstat_values[dns_nsstatscounter_max]; + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "zone"); + + dns_zone_name(zone, buf, sizeof(buf)); + xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"); + xmlTextWriterWriteString(writer, ISC_XMLCHAR buf); + xmlTextWriterEndElement(writer); + + rdclass = dns_zone_getclass(zone); + dns_rdataclass_format(rdclass, buf, sizeof(buf)); + xmlTextWriterStartElement(writer, ISC_XMLCHAR "rdataclass"); + xmlTextWriterWriteString(writer, ISC_XMLCHAR buf); + xmlTextWriterEndElement(writer); + + serial = dns_zone_getserial(zone); + xmlTextWriterStartElement(writer, ISC_XMLCHAR "serial"); + xmlTextWriterWriteFormatString(writer, "%u", serial); + xmlTextWriterEndElement(writer); + + zonestats = dns_zone_getrequeststats(zone); + if (zonestats != NULL) { + xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"); + dump_counters(zonestats, statsformat_xml, writer, NULL, + nsstats_xmldesc, dns_nsstatscounter_max, + nsstats_index, nsstat_values, + ISC_STATSDUMP_VERBOSE); + xmlTextWriterEndElement(writer); /* counters */ + } + + xmlTextWriterEndElement(writer); /* zone */ + + return (ISC_R_SUCCESS); +} + +static void +generatexml(ns_server_t *server, int *buflen, xmlChar **buf) { + char boottime[sizeof "yyyy-mm-ddThh:mm:ssZ"]; + char nowstr[sizeof "yyyy-mm-ddThh:mm:ssZ"]; + isc_time_t now; + xmlTextWriterPtr writer; + xmlDocPtr doc; + int xmlrc; + dns_view_t *view; + stats_dumparg_t dumparg; + dns_stats_t *cachestats; + isc_uint64_t nsstat_values[dns_nsstatscounter_max]; + isc_uint64_t resstat_values[dns_resstatscounter_max]; + isc_uint64_t zonestat_values[dns_zonestatscounter_max]; + isc_uint64_t sockstat_values[isc_sockstatscounter_max]; + + isc_time_now(&now); + isc_time_formatISO8601(&ns_g_boottime, boottime, sizeof boottime); + isc_time_formatISO8601(&now, nowstr, sizeof nowstr); + + writer = xmlNewTextWriterDoc(&doc, 0); + TRY0(xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL)); + TRY0(xmlTextWriterWritePI(writer, ISC_XMLCHAR "xml-stylesheet", + ISC_XMLCHAR "type=\"text/xsl\" href=\"/bind9.xsl\"")); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "isc")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version", + ISC_XMLCHAR "1.0")); + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "bind")); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "statistics")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version", + ISC_XMLCHAR "2.0")); + + /* Set common fields for statistics dump */ + dumparg.type = statsformat_xml; + dumparg.arg = writer; + + /* + * Start by rendering the views we know of here. For each view we + * know of, call its rendering function. + */ + view = ISC_LIST_HEAD(server->viewlist); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "views")); + while (view != NULL) { + xmlTextWriterStartElement(writer, ISC_XMLCHAR "view"); + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"); + xmlTextWriterWriteString(writer, ISC_XMLCHAR view->name); + xmlTextWriterEndElement(writer); + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "zones"); + dns_zt_apply(view->zonetable, ISC_FALSE, zone_xmlrender, + writer); + xmlTextWriterEndElement(writer); + + if (view->resquerystats != NULL) { + dns_rdatatypestats_dump(view->resquerystats, + rdtypestat_dump, &dumparg, 0); + } + + if (view->resstats != NULL) { + dump_counters(view->resstats, statsformat_xml, writer, + "resstat", resstats_xmldesc, + dns_resstatscounter_max, resstats_index, + resstat_values, ISC_STATSDUMP_VERBOSE); + } + + cachestats = dns_db_getrrsetstats(view->cachedb); + if (cachestats != NULL) { + xmlTextWriterStartElement(writer, + ISC_XMLCHAR "cache"); + dns_rdatasetstats_dump(cachestats, rdatasetstats_dump, + &dumparg, 0); + xmlTextWriterEndElement(writer); /* cache */ + } + + xmlTextWriterEndElement(writer); /* view */ + + view = ISC_LIST_NEXT(view, link); + } + TRY0(xmlTextWriterEndElement(writer)); /* views */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "socketmgr")); + isc_socketmgr_renderxml(ns_g_socketmgr, writer); + TRY0(xmlTextWriterEndElement(writer)); /* socketmgr */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "taskmgr")); + isc_taskmgr_renderxml(ns_g_taskmgr, writer); + TRY0(xmlTextWriterEndElement(writer)); /* taskmgr */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "server")); + xmlTextWriterStartElement(writer, ISC_XMLCHAR "boot-time"); + xmlTextWriterWriteString(writer, ISC_XMLCHAR boottime); + xmlTextWriterEndElement(writer); + xmlTextWriterStartElement(writer, ISC_XMLCHAR "current-time"); + xmlTextWriterWriteString(writer, ISC_XMLCHAR nowstr); + xmlTextWriterEndElement(writer); + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "requests")); + dns_opcodestats_dump(server->opcodestats, opcodestat_dump, &dumparg, + 0); + xmlTextWriterEndElement(writer); /* requests */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "queries-in")); + dns_rdatatypestats_dump(server->rcvquerystats, rdtypestat_dump, + &dumparg, 0); + xmlTextWriterEndElement(writer); /* queries-in */ + + dump_counters(server->nsstats, statsformat_xml, writer, + "nsstat", nsstats_xmldesc, dns_nsstatscounter_max, + nsstats_index, nsstat_values, ISC_STATSDUMP_VERBOSE); + + dump_counters(server->zonestats, statsformat_xml, writer, "zonestat", + zonestats_xmldesc, dns_zonestatscounter_max, + zonestats_index, zonestat_values, ISC_STATSDUMP_VERBOSE); + + /* + * Most of the common resolver statistics entries are 0, so we don't + * use the verbose dump here. + */ + dump_counters(server->resolverstats, statsformat_xml, writer, "resstat", + resstats_xmldesc, dns_resstatscounter_max, resstats_index, + resstat_values, 0); + + dump_counters(server->sockstats, statsformat_xml, writer, "sockstat", + sockstats_xmldesc, isc_sockstatscounter_max, + sockstats_index, sockstat_values, ISC_STATSDUMP_VERBOSE); + + xmlTextWriterEndElement(writer); /* server */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "memory")); + isc_mem_renderxml(writer); + TRY0(xmlTextWriterEndElement(writer)); /* memory */ + + TRY0(xmlTextWriterEndElement(writer)); /* statistics */ + TRY0(xmlTextWriterEndElement(writer)); /* bind */ + TRY0(xmlTextWriterEndElement(writer)); /* isc */ + + TRY0(xmlTextWriterEndDocument(writer)); + + xmlFreeTextWriter(writer); + + xmlDocDumpFormatMemoryEnc(doc, buf, buflen, "UTF-8", 1); + xmlFreeDoc(doc); +} + +static void +wrap_xmlfree(isc_buffer_t *buffer, void *arg) { + UNUSED(arg); + + xmlFree(isc_buffer_base(buffer)); +} + +static isc_result_t +render_index(const char *url, const char *querystring, void *arg, + unsigned int *retcode, const char **retmsg, const char **mimetype, + isc_buffer_t *b, isc_httpdfree_t **freecb, + void **freecb_args) +{ + unsigned char *msg; + int msglen; + ns_server_t *server = arg; + + UNUSED(url); + UNUSED(querystring); + + generatexml(server, &msglen, &msg); + + *retcode = 200; + *retmsg = "OK"; + *mimetype = "text/xml"; + isc_buffer_reinit(b, msg, msglen); + isc_buffer_add(b, msglen); + *freecb = wrap_xmlfree; + *freecb_args = NULL; + + return (ISC_R_SUCCESS); +} + +#endif /* HAVE_LIBXML2 */ + +static isc_result_t +render_xsl(const char *url, const char *querystring, void *args, + unsigned int *retcode, const char **retmsg, const char **mimetype, + isc_buffer_t *b, isc_httpdfree_t **freecb, + void **freecb_args) +{ + UNUSED(url); + UNUSED(querystring); + UNUSED(args); + + *retcode = 200; + *retmsg = "OK"; + *mimetype = "text/xslt+xml"; + isc_buffer_reinit(b, xslmsg, strlen(xslmsg)); + isc_buffer_add(b, strlen(xslmsg)); + *freecb = NULL; + *freecb_args = NULL; + + return (ISC_R_SUCCESS); +} + +static void +shutdown_listener(ns_statschannel_t *listener) { + char socktext[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_format(&listener->address, socktext, sizeof(socktext)); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,NS_LOGMODULE_SERVER, + ISC_LOG_NOTICE, "stopping statistics channel on %s", + socktext); + + isc_httpdmgr_shutdown(&listener->httpdmgr); +} + +static isc_boolean_t +client_ok(const isc_sockaddr_t *fromaddr, void *arg) { + ns_statschannel_t *listener = arg; + isc_netaddr_t netaddr; + char socktext[ISC_SOCKADDR_FORMATSIZE]; + int match; + + REQUIRE(listener != NULL); + + isc_netaddr_fromsockaddr(&netaddr, fromaddr); + + LOCK(&listener->lock); + if (dns_acl_match(&netaddr, NULL, listener->acl, &ns_g_server->aclenv, + &match, NULL) == ISC_R_SUCCESS && match > 0) { + UNLOCK(&listener->lock); + return (ISC_TRUE); + } + UNLOCK(&listener->lock); + + isc_sockaddr_format(fromaddr, socktext, sizeof(socktext)); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_WARNING, + "rejected statistics connection from %s", socktext); + + return (ISC_FALSE); +} + +static void +destroy_listener(void *arg) { + ns_statschannel_t *listener = arg; + + REQUIRE(listener != NULL); + REQUIRE(!ISC_LINK_LINKED(listener, link)); + + /* We don't have to acquire the lock here since it's already unlinked */ + dns_acl_detach(&listener->acl); + + DESTROYLOCK(&listener->lock); + isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener)); +} + +static isc_result_t +add_listener(ns_server_t *server, ns_statschannel_t **listenerp, + const cfg_obj_t *listen_params, const cfg_obj_t *config, + isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, + const char *socktext) +{ + isc_result_t result; + ns_statschannel_t *listener; + isc_task_t *task = NULL; + isc_socket_t *sock = NULL; + const cfg_obj_t *allow; + dns_acl_t *new_acl = NULL; + + listener = isc_mem_get(server->mctx, sizeof(*listener)); + if (listener == NULL) + return (ISC_R_NOMEMORY); + + listener->httpdmgr = NULL; + listener->address = *addr; + listener->acl = NULL; + listener->mctx = NULL; + ISC_LINK_INIT(listener, link); + + result = isc_mutex_init(&listener->lock); + if (result != ISC_R_SUCCESS) { + isc_mem_put(server->mctx, listener, sizeof(*listener)); + return (ISC_R_FAILURE); + } + + isc_mem_attach(server->mctx, &listener->mctx); + + allow = cfg_tuple_get(listen_params, "allow"); + if (allow != NULL && cfg_obj_islist(allow)) { + result = cfg_acl_fromconfig(allow, config, ns_g_lctx, + aclconfctx, listener->mctx, 0, + &new_acl); + } else + result = dns_acl_any(listener->mctx, &new_acl); + if (result != ISC_R_SUCCESS) + goto cleanup; + dns_acl_attach(new_acl, &listener->acl); + dns_acl_detach(&new_acl); + + result = isc_task_create(ns_g_taskmgr, 0, &task); + if (result != ISC_R_SUCCESS) + goto cleanup; + isc_task_setname(task, "statchannel", NULL); + + result = isc_socket_create(ns_g_socketmgr, isc_sockaddr_pf(addr), + isc_sockettype_tcp, &sock); + if (result != ISC_R_SUCCESS) + goto cleanup; + isc_socket_setname(sock, "statchannel", NULL); + +#ifndef ISC_ALLOW_MAPPED + isc_socket_ipv6only(sock, ISC_TRUE); +#endif + + result = isc_socket_bind(sock, addr, ISC_SOCKET_REUSEADDRESS); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = isc_httpdmgr_create(server->mctx, sock, task, client_ok, + destroy_listener, listener, ns_g_timermgr, + &listener->httpdmgr); + if (result != ISC_R_SUCCESS) + goto cleanup; + +#ifdef HAVE_LIBXML2 + isc_httpdmgr_addurl(listener->httpdmgr, "/", render_index, server); +#endif + isc_httpdmgr_addurl(listener->httpdmgr, "/bind9.xsl", render_xsl, + server); + + *listenerp = listener; + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_NOTICE, + "statistics channel listening on %s", socktext); + +cleanup: + if (result != ISC_R_SUCCESS) { + if (listener->acl != NULL) + dns_acl_detach(&listener->acl); + DESTROYLOCK(&listener->lock); + isc_mem_putanddetach(&listener->mctx, listener, + sizeof(*listener)); + } + if (task != NULL) + isc_task_detach(&task); + if (sock != NULL) + isc_socket_detach(&sock); + + return (result); +} + +static void +update_listener(ns_server_t *server, ns_statschannel_t **listenerp, + const cfg_obj_t *listen_params, const cfg_obj_t *config, + isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, + const char *socktext) +{ + ns_statschannel_t *listener; + const cfg_obj_t *allow = NULL; + dns_acl_t *new_acl = NULL; + isc_result_t result = ISC_R_SUCCESS; + + for (listener = ISC_LIST_HEAD(server->statschannels); + listener != NULL; + listener = ISC_LIST_NEXT(listener, link)) + if (isc_sockaddr_equal(addr, &listener->address)) + break; + + if (listener == NULL) { + *listenerp = NULL; + return; + } + + /* + * Now, keep the old access list unless a new one can be made. + */ + allow = cfg_tuple_get(listen_params, "allow"); + if (allow != NULL && cfg_obj_islist(allow)) { + result = cfg_acl_fromconfig(allow, config, ns_g_lctx, + aclconfctx, listener->mctx, 0, + &new_acl); + } else + result = dns_acl_any(listener->mctx, &new_acl); + + if (result == ISC_R_SUCCESS) { + LOCK(&listener->lock); + + dns_acl_detach(&listener->acl); + dns_acl_attach(new_acl, &listener->acl); + dns_acl_detach(&new_acl); + + UNLOCK(&listener->lock); + } else { + cfg_obj_log(listen_params, ns_g_lctx, ISC_LOG_WARNING, + "couldn't install new acl for " + "statistics channel %s: %s", + socktext, isc_result_totext(result)); + } + + *listenerp = listener; +} + +isc_result_t +ns_statschannels_configure(ns_server_t *server, const cfg_obj_t *config, + cfg_aclconfctx_t *aclconfctx) +{ + ns_statschannel_t *listener, *listener_next; + ns_statschannellist_t new_listeners; + const cfg_obj_t *statschannellist = NULL; + const cfg_listelt_t *element, *element2; + char socktext[ISC_SOCKADDR_FORMATSIZE]; + + RUNTIME_CHECK(isc_once_do(&once, init_desc) == ISC_R_SUCCESS); + + ISC_LIST_INIT(new_listeners); + + /* + * Get the list of named.conf 'statistics-channels' statements. + */ + (void)cfg_map_get(config, "statistics-channels", &statschannellist); + + /* + * Run through the new address/port list, noting sockets that are + * already being listened on and moving them to the new list. + * + * Identifying duplicate addr/port combinations is left to either + * the underlying config code, or to the bind attempt getting an + * address-in-use error. + */ + if (statschannellist != NULL) { +#ifndef HAVE_LIBXML2 + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_WARNING, + "statistics-channels specified but not effective " + "due to missing XML library"); +#endif + + for (element = cfg_list_first(statschannellist); + element != NULL; + element = cfg_list_next(element)) { + const cfg_obj_t *statschannel; + const cfg_obj_t *listenercfg = NULL; + + statschannel = cfg_listelt_value(element); + (void)cfg_map_get(statschannel, "inet", + &listenercfg); + if (listenercfg == NULL) + continue; + + for (element2 = cfg_list_first(listenercfg); + element2 != NULL; + element2 = cfg_list_next(element2)) { + const cfg_obj_t *listen_params; + const cfg_obj_t *obj; + isc_sockaddr_t addr; + + listen_params = cfg_listelt_value(element2); + + obj = cfg_tuple_get(listen_params, "address"); + addr = *cfg_obj_assockaddr(obj); + if (isc_sockaddr_getport(&addr) == 0) + isc_sockaddr_setport(&addr, NS_STATSCHANNEL_HTTPPORT); + + isc_sockaddr_format(&addr, socktext, + sizeof(socktext)); + + isc_log_write(ns_g_lctx, + NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, + ISC_LOG_DEBUG(9), + "processing statistics " + "channel %s", + socktext); + + update_listener(server, &listener, + listen_params, config, &addr, + aclconfctx, socktext); + + if (listener != NULL) { + /* + * Remove the listener from the old + * list, so it won't be shut down. + */ + ISC_LIST_UNLINK(server->statschannels, + listener, link); + } else { + /* + * This is a new listener. + */ + isc_result_t r; + + r = add_listener(server, &listener, + listen_params, config, + &addr, aclconfctx, + socktext); + if (r != ISC_R_SUCCESS) { + cfg_obj_log(listen_params, + ns_g_lctx, + ISC_LOG_WARNING, + "couldn't allocate " + "statistics channel" + " %s: %s", + socktext, + isc_result_totext(r)); + } + } + + if (listener != NULL) + ISC_LIST_APPEND(new_listeners, listener, + link); + } + } + } + + for (listener = ISC_LIST_HEAD(server->statschannels); + listener != NULL; + listener = listener_next) { + listener_next = ISC_LIST_NEXT(listener, link); + ISC_LIST_UNLINK(server->statschannels, listener, link); + shutdown_listener(listener); + } + + ISC_LIST_APPENDLIST(server->statschannels, new_listeners, link); + return (ISC_R_SUCCESS); +} + +void +ns_statschannels_shutdown(ns_server_t *server) { + ns_statschannel_t *listener; + + while ((listener = ISC_LIST_HEAD(server->statschannels)) != NULL) { + ISC_LIST_UNLINK(server->statschannels, listener, link); + shutdown_listener(listener); + } +} + +isc_result_t +ns_stats_dump(ns_server_t *server, FILE *fp) { + isc_stdtime_t now; + isc_result_t result; + dns_view_t *view; + dns_zone_t *zone, *next; + stats_dumparg_t dumparg; + isc_uint64_t nsstat_values[dns_nsstatscounter_max]; + isc_uint64_t resstat_values[dns_resstatscounter_max]; + isc_uint64_t zonestat_values[dns_zonestatscounter_max]; + isc_uint64_t sockstat_values[isc_sockstatscounter_max]; + + RUNTIME_CHECK(isc_once_do(&once, init_desc) == ISC_R_SUCCESS); + + /* Set common fields */ + dumparg.type = statsformat_file; + dumparg.arg = fp; + + isc_stdtime_get(&now); + fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now); + + fprintf(fp, "++ Incoming Requests ++\n"); + dns_opcodestats_dump(server->opcodestats, opcodestat_dump, &dumparg, 0); + + fprintf(fp, "++ Incoming Queries ++\n"); + dns_rdatatypestats_dump(server->rcvquerystats, rdtypestat_dump, + &dumparg, 0); + + fprintf(fp, "++ Outgoing Queries ++\n"); + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) { + if (view->resquerystats == NULL) + continue; + if (strcmp(view->name, "_default") == 0) + fprintf(fp, "[View: default]\n"); + else + fprintf(fp, "[View: %s]\n", view->name); + dns_rdatatypestats_dump(view->resquerystats, rdtypestat_dump, + &dumparg, 0); + } + + fprintf(fp, "++ Name Server Statistics ++\n"); + dump_counters(server->nsstats, statsformat_file, fp, NULL, + nsstats_desc, dns_nsstatscounter_max, nsstats_index, + nsstat_values, 0); + + fprintf(fp, "++ Zone Maintenance Statistics ++\n"); + dump_counters(server->zonestats, statsformat_file, fp, NULL, + zonestats_desc, dns_zonestatscounter_max, + zonestats_index, zonestat_values, 0); + + fprintf(fp, "++ Resolver Statistics ++\n"); + fprintf(fp, "[Common]\n"); + dump_counters(server->resolverstats, statsformat_file, fp, NULL, + resstats_desc, dns_resstatscounter_max, resstats_index, + resstat_values, 0); + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) { + if (view->resstats == NULL) + continue; + if (strcmp(view->name, "_default") == 0) + fprintf(fp, "[View: default]\n"); + else + fprintf(fp, "[View: %s]\n", view->name); + dump_counters(view->resstats, statsformat_file, fp, NULL, + resstats_desc, dns_resstatscounter_max, + resstats_index, resstat_values, 0); + } + + fprintf(fp, "++ Cache DB RRsets ++\n"); + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) { + dns_stats_t *cachestats; + + cachestats = dns_db_getrrsetstats(view->cachedb); + if (cachestats == NULL) + continue; + if (strcmp(view->name, "_default") == 0) + fprintf(fp, "[View: default]\n"); + else + fprintf(fp, "[View: %s]\n", view->name); + dns_rdatasetstats_dump(cachestats, rdatasetstats_dump, &dumparg, + 0); + } + + fprintf(fp, "++ Socket I/O Statistics ++\n"); + dump_counters(server->sockstats, statsformat_file, fp, NULL, + sockstats_desc, isc_sockstatscounter_max, sockstats_index, + sockstat_values, 0); + + fprintf(fp, "++ Per Zone Query Statistics ++\n"); + zone = NULL; + for (result = dns_zone_first(server->zonemgr, &zone); + result == ISC_R_SUCCESS; + next = NULL, result = dns_zone_next(zone, &next), zone = next) + { + isc_stats_t *zonestats = dns_zone_getrequeststats(zone); + if (zonestats != NULL) { + char zonename[DNS_NAME_FORMATSIZE]; + + dns_name_format(dns_zone_getorigin(zone), + zonename, sizeof(zonename)); + view = dns_zone_getview(zone); + + fprintf(fp, "[%s", zonename); + if (strcmp(view->name, "_default") != 0) + fprintf(fp, " (view: %s)", view->name); + fprintf(fp, "]\n"); + + dump_counters(zonestats, statsformat_file, fp, NULL, + nsstats_desc, dns_nsstatscounter_max, + nsstats_index, nsstat_values, 0); + } + } + + fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now); + + return (ISC_R_SUCCESS); /* this function currently always succeeds */ +} diff --git a/contrib/bind-9.5.2/bin/named/tkeyconf.c b/contrib/bind-9.5.2/bin/named/tkeyconf.c new file mode 100644 index 0000000000..82cf573bf7 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/tkeyconf.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * 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: tkeyconf.c,v 1.29 2007/06/19 23:46:59 tbox Exp $ */ + +/*! \file */ + +#include + +#include +#include /* Required for HP/UX (and others?) */ +#include + +#include + +#include +#include +#include +#include + +#include + +#include + +#define RETERR(x) do { \ + result = (x); \ + if (result != ISC_R_SUCCESS) \ + goto failure; \ + } while (0) + +#include +#define LOG(msg) \ + isc_log_write(ns_g_lctx, \ + NS_LOGCATEGORY_GENERAL, \ + NS_LOGMODULE_SERVER, \ + ISC_LOG_ERROR, \ + "%s", msg) + +isc_result_t +ns_tkeyctx_fromconfig(const cfg_obj_t *options, isc_mem_t *mctx, + isc_entropy_t *ectx, dns_tkeyctx_t **tctxp) +{ + isc_result_t result; + dns_tkeyctx_t *tctx = NULL; + const char *s; + isc_uint32_t n; + dns_fixedname_t fname; + dns_name_t *name; + isc_buffer_t b; + const cfg_obj_t *obj; + int type; + + result = dns_tkeyctx_create(mctx, ectx, &tctx); + if (result != ISC_R_SUCCESS) + return (result); + + obj = NULL; + result = cfg_map_get(options, "tkey-dhkey", &obj); + if (result == ISC_R_SUCCESS) { + s = cfg_obj_asstring(cfg_tuple_get(obj, "name")); + n = cfg_obj_asuint32(cfg_tuple_get(obj, "keyid")); + isc_buffer_init(&b, s, strlen(s)); + isc_buffer_add(&b, strlen(s)); + dns_fixedname_init(&fname); + name = dns_fixedname_name(&fname); + RETERR(dns_name_fromtext(name, &b, dns_rootname, + ISC_FALSE, NULL)); + type = DST_TYPE_PUBLIC|DST_TYPE_PRIVATE|DST_TYPE_KEY; + RETERR(dst_key_fromfile(name, (dns_keytag_t) n, DNS_KEYALG_DH, + type, NULL, mctx, &tctx->dhkey)); + } + + obj = NULL; + result = cfg_map_get(options, "tkey-domain", &obj); + if (result == ISC_R_SUCCESS) { + s = cfg_obj_asstring(obj); + isc_buffer_init(&b, s, strlen(s)); + isc_buffer_add(&b, strlen(s)); + dns_fixedname_init(&fname); + name = dns_fixedname_name(&fname); + RETERR(dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, + NULL)); + tctx->domain = isc_mem_get(mctx, sizeof(dns_name_t)); + if (tctx->domain == NULL) { + result = ISC_R_NOMEMORY; + goto failure; + } + dns_name_init(tctx->domain, NULL); + RETERR(dns_name_dup(name, mctx, tctx->domain)); + } + + obj = NULL; + result = cfg_map_get(options, "tkey-gssapi-credential", &obj); + if (result == ISC_R_SUCCESS) { + s = cfg_obj_asstring(obj); + + isc_buffer_init(&b, s, strlen(s)); + isc_buffer_add(&b, strlen(s)); + dns_fixedname_init(&fname); + name = dns_fixedname_name(&fname); + RETERR(dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, + NULL)); + RETERR(dst_gssapi_acquirecred(name, ISC_FALSE, + &tctx->gsscred)); + } + + *tctxp = tctx; + return (ISC_R_SUCCESS); + + failure: + dns_tkeyctx_destroy(&tctx); + return (result); +} + diff --git a/contrib/bind-9.5.2/bin/named/tsigconf.c b/contrib/bind-9.5.2/bin/named/tsigconf.c new file mode 100644 index 0000000000..b3c6e023db --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/tsigconf.c @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * 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: tsigconf.c,v 1.30 2007/06/19 23:46:59 tbox Exp $ */ + +/*! \file */ + +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include +#include + +static isc_result_t +add_initial_keys(const cfg_obj_t *list, dns_tsig_keyring_t *ring, + isc_mem_t *mctx) +{ + dns_tsigkey_t *tsigkey = NULL; + const cfg_listelt_t *element; + const cfg_obj_t *key = NULL; + const char *keyid = NULL; + unsigned char *secret = NULL; + int secretalloc = 0; + int secretlen = 0; + isc_result_t ret; + isc_stdtime_t now; + isc_uint16_t bits; + + for (element = cfg_list_first(list); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *algobj = NULL; + const cfg_obj_t *secretobj = NULL; + dns_name_t keyname; + dns_name_t *alg; + const char *algstr; + char keynamedata[1024]; + isc_buffer_t keynamesrc, keynamebuf; + const char *secretstr; + isc_buffer_t secretbuf; + + key = cfg_listelt_value(element); + keyid = cfg_obj_asstring(cfg_map_getname(key)); + + algobj = NULL; + secretobj = NULL; + (void)cfg_map_get(key, "algorithm", &algobj); + (void)cfg_map_get(key, "secret", &secretobj); + INSIST(algobj != NULL && secretobj != NULL); + + /* + * Create the key name. + */ + dns_name_init(&keyname, NULL); + isc_buffer_init(&keynamesrc, keyid, strlen(keyid)); + isc_buffer_add(&keynamesrc, strlen(keyid)); + isc_buffer_init(&keynamebuf, keynamedata, sizeof(keynamedata)); + ret = dns_name_fromtext(&keyname, &keynamesrc, dns_rootname, + ISC_TRUE, &keynamebuf); + if (ret != ISC_R_SUCCESS) + goto failure; + + /* + * Create the algorithm. + */ + algstr = cfg_obj_asstring(algobj); + if (ns_config_getkeyalgorithm(algstr, &alg, &bits) + != ISC_R_SUCCESS) { + cfg_obj_log(algobj, ns_g_lctx, ISC_LOG_ERROR, + "key '%s': has a unsupported algorithm '%s'", + keyid, algstr); + ret = DNS_R_BADALG; + goto failure; + } + + secretstr = cfg_obj_asstring(secretobj); + secretalloc = secretlen = strlen(secretstr) * 3 / 4; + secret = isc_mem_get(mctx, secretlen); + if (secret == NULL) { + ret = ISC_R_NOMEMORY; + goto failure; + } + isc_buffer_init(&secretbuf, secret, secretlen); + ret = isc_base64_decodestring(secretstr, &secretbuf); + if (ret != ISC_R_SUCCESS) + goto failure; + secretlen = isc_buffer_usedlength(&secretbuf); + + isc_stdtime_get(&now); + ret = dns_tsigkey_create(&keyname, alg, secret, secretlen, + ISC_FALSE, NULL, now, now, + mctx, ring, &tsigkey); + isc_mem_put(mctx, secret, secretalloc); + secret = NULL; + if (ret != ISC_R_SUCCESS) + goto failure; + /* + * Set digest bits. + */ + dst_key_setbits(tsigkey->key, bits); + dns_tsigkey_detach(&tsigkey); + } + + return (ISC_R_SUCCESS); + + failure: + cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR, + "configuring key '%s': %s", keyid, + isc_result_totext(ret)); + + if (secret != NULL) + isc_mem_put(mctx, secret, secretalloc); + return (ret); +} + +isc_result_t +ns_tsigkeyring_fromconfig(const cfg_obj_t *config, const cfg_obj_t *vconfig, + isc_mem_t *mctx, dns_tsig_keyring_t **ringp) +{ + const cfg_obj_t *maps[3]; + const cfg_obj_t *keylist; + dns_tsig_keyring_t *ring = NULL; + isc_result_t result; + int i; + + i = 0; + if (config != NULL) + maps[i++] = config; + if (vconfig != NULL) + maps[i++] = cfg_tuple_get(vconfig, "options"); + maps[i] = NULL; + + result = dns_tsigkeyring_create(mctx, &ring); + if (result != ISC_R_SUCCESS) + return (result); + + for (i = 0; ; i++) { + if (maps[i] == NULL) + break; + keylist = NULL; + result = cfg_map_get(maps[i], "key", &keylist); + if (result != ISC_R_SUCCESS) + continue; + result = add_initial_keys(keylist, ring, mctx); + if (result != ISC_R_SUCCESS) + goto failure; + } + + *ringp = ring; + return (ISC_R_SUCCESS); + + failure: + dns_tsigkeyring_destroy(&ring); + return (result); +} diff --git a/contrib/bind-9.5.2/bin/named/unix/include/named/os.h b/contrib/bind-9.5.2/bin/named/unix/include/named/os.h new file mode 100644 index 0000000000..1ab86aa290 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/unix/include/named/os.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2002 Internet Software Consortium. + * + * 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: os.h,v 1.27.128.2 2008/10/24 01:44:15 tbox Exp $ */ + +#ifndef NS_OS_H +#define NS_OS_H 1 + +/*! \file */ + +#include + +void +ns_os_init(const char *progname); + +void +ns_os_daemonize(void); + +void +ns_os_opendevnull(void); + +void +ns_os_closedevnull(void); + +void +ns_os_chroot(const char *root); + +void +ns_os_inituserinfo(const char *username); + +void +ns_os_changeuser(void); + +void +ns_os_adjustnofile(void); + +void +ns_os_minprivs(void); + +void +ns_os_writepidfile(const char *filename, isc_boolean_t first_time); +void +ns_os_shutdown(void); + +isc_result_t +ns_os_gethostname(char *buf, size_t len); + +void +ns_os_shutdownmsg(char *command, isc_buffer_t *text); + +void +ns_os_tzset(void); + +void +ns_os_started(void); + +#endif /* NS_OS_H */ diff --git a/contrib/bind-9.5.2/bin/named/unix/os.c b/contrib/bind-9.5.2/bin/named/unix/os.c new file mode 100644 index 0000000000..337d230ec8 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/unix/os.c @@ -0,0 +1,802 @@ +/* + * 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 + * 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: os.c,v 1.79.128.13 2009/03/02 03:07:05 marka Exp $ */ + +/*! \file */ + +#include +#include + +#include /* dev_t FreeBSD 2.1 */ +#include + +#include +#include +#include +#include /* Required for initgroups() on IRIX. */ +#include +#include +#include +#include +#include +#ifdef HAVE_TZSET +#include +#endif +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#ifdef HAVE_LIBSCF +#include +#endif + +static char *pidfile = NULL; +static int devnullfd = -1; + +#ifndef ISC_FACILITY +#define ISC_FACILITY LOG_DAEMON +#endif + +/* + * If there's no , we don't care about + */ +#ifndef HAVE_LINUX_CAPABILITY_H +#undef HAVE_SYS_PRCTL_H +#endif + +/* + * Linux defines: + * (T) HAVE_LINUXTHREADS + * (C) HAVE_SYS_CAPABILITY_H (or HAVE_LINUX_CAPABILITY_H) + * (P) HAVE_SYS_PRCTL_H + * The possible cases are: + * none: setuid() normally + * T: no setuid() + * C: setuid() normally, drop caps (keep CAP_SETUID) + * T+C: no setuid(), drop caps (don't keep CAP_SETUID) + * T+C+P: setuid() early, drop caps (keep CAP_SETUID) + * C+P: setuid() normally, drop caps (keep CAP_SETUID) + * P: not possible + * T+P: not possible + * + * if (C) + * caps = BIND_SERVICE + CHROOT + SETGID + * if ((T && C && P) || !T) + * caps += SETUID + * endif + * capset(caps) + * endif + * if (T && C && P && -u) + * setuid() + * else if (T && -u) + * fail + * --> start threads + * if (!T && -u) + * setuid() + * if (C && (P || !-u)) + * caps = BIND_SERVICE + * capset(caps) + * endif + * + * It will be nice when Linux threads work properly with setuid(). + */ + +#ifdef HAVE_LINUXTHREADS +static pid_t mainpid = 0; +#endif + +static struct passwd *runas_pw = NULL; +static isc_boolean_t done_setuid = ISC_FALSE; +static int dfd[2] = { -1, -1 }; + +#ifdef HAVE_LINUX_CAPABILITY_H + +static isc_boolean_t non_root = ISC_FALSE; +static isc_boolean_t non_root_caps = ISC_FALSE; + +#ifdef HAVE_SYS_CAPABILITY_H +#include +#else +/*% + * We define _LINUX_FS_H to prevent it from being included. We don't need + * anything from it, and the files it includes cause warnings with 2.2 + * kernels, and compilation failures (due to conflicts between + * and ) on 2.3 kernels. + */ +#define _LINUX_FS_H +#include +#include +#ifndef SYS_capset +#ifndef __NR_capset +#include /* Slackware 4.0 needs this. */ +#endif /* __NR_capset */ +#define SYS_capset __NR_capset +#endif /* SYS_capset */ +#endif /* HAVE_SYS_CAPABILITY_H */ + +#ifdef HAVE_SYS_PRCTL_H +#include /* Required for prctl(). */ + +/* + * If the value of PR_SET_KEEPCAPS is not in , define it + * here. This allows setuid() to work on systems running a new enough + * kernel but with /usr/include/linux pointing to "standard" kernel + * headers. + */ +#ifndef PR_SET_KEEPCAPS +#define PR_SET_KEEPCAPS 8 +#endif + +#endif /* HAVE_SYS_PRCTL_H */ + +#ifdef HAVE_LIBCAP +#define SETCAPS_FUNC "cap_set_proc " +#else +typedef unsigned int cap_t; +#define SETCAPS_FUNC "syscall(capset) " +#endif /* HAVE_LIBCAP */ + +static void +linux_setcaps(cap_t caps) { +#ifndef HAVE_LIBCAP + struct __user_cap_header_struct caphead; + struct __user_cap_data_struct cap; +#endif + char strbuf[ISC_STRERRORSIZE]; + + if ((getuid() != 0 && !non_root_caps) || non_root) + return; +#ifndef HAVE_LIBCAP + memset(&caphead, 0, sizeof(caphead)); + caphead.version = _LINUX_CAPABILITY_VERSION; + caphead.pid = 0; + memset(&cap, 0, sizeof(cap)); + cap.effective = caps; + cap.permitted = caps; + cap.inheritable = 0; +#endif +#ifdef HAVE_LIBCAP + if (cap_set_proc(caps) < 0) { +#else + if (syscall(SYS_capset, &caphead, &cap) < 0) { +#endif + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlyfatal(SETCAPS_FUNC "failed: %s:" + " please ensure that the capset kernel" + " module is loaded. see insmod(8)", + strbuf); + } +} + +#ifdef HAVE_LIBCAP +#define SET_CAP(flag) \ + do { \ + capval = (flag); \ + cap_flag_value_t curval; \ + err = cap_get_flag(curcaps, capval, CAP_PERMITTED, &curval); \ + if (err != -1 && curval) { \ + err = cap_set_flag(caps, CAP_EFFECTIVE, 1, &capval, CAP_SET); \ + if (err == -1) { \ + isc__strerror(errno, strbuf, sizeof(strbuf)); \ + ns_main_earlyfatal("cap_set_proc failed: %s", strbuf); \ + } \ + \ + err = cap_set_flag(caps, CAP_PERMITTED, 1, &capval, CAP_SET); \ + if (err == -1) { \ + isc__strerror(errno, strbuf, sizeof(strbuf)); \ + ns_main_earlyfatal("cap_set_proc failed: %s", strbuf); \ + } \ + } \ + } while (0) +#define INIT_CAP \ + do { \ + caps = cap_init(); \ + if (caps == NULL) { \ + isc__strerror(errno, strbuf, sizeof(strbuf)); \ + ns_main_earlyfatal("cap_init failed: %s", strbuf); \ + } \ + curcaps = cap_get_proc(); \ + if (curcaps == NULL) { \ + isc__strerror(errno, strbuf, sizeof(strbuf)); \ + ns_main_earlyfatal("cap_get_proc failed: %s", strbuf); \ + } \ + } while (0) +#define FREE_CAP \ + { \ + cap_free(caps); \ + cap_free(curcaps); \ + } while (0) +#else +#define SET_CAP(flag) do { caps |= (1 << (flag)); } while (0) +#define INIT_CAP do { caps = 0; } while (0) +#endif /* HAVE_LIBCAP */ + +static void +linux_initialprivs(void) { + cap_t caps; +#ifdef HAVE_LIBCAP + cap_t curcaps; + cap_value_t capval; + char strbuf[ISC_STRERRORSIZE]; + int err; +#endif + + /*% + * We don't need most privileges, so we drop them right away. + * Later on linux_minprivs() will be called, which will drop our + * capabilities to the minimum needed to run the server. + */ + INIT_CAP; + + /* + * We need to be able to bind() to privileged ports, notably port 53! + */ + SET_CAP(CAP_NET_BIND_SERVICE); + + /* + * We need chroot() initially too. + */ + SET_CAP(CAP_SYS_CHROOT); + +#if defined(HAVE_SYS_PRCTL_H) || !defined(HAVE_LINUXTHREADS) + /* + * We can setuid() only if either the kernel supports keeping + * capabilities after setuid() (which we don't know until we've + * tried) or we're not using threads. If either of these is + * true, we want the setuid capability. + */ + SET_CAP(CAP_SETUID); +#endif + + /* + * Since we call initgroups, we need this. + */ + SET_CAP(CAP_SETGID); + + /* + * Without this, we run into problems reading a configuration file + * owned by a non-root user and non-world-readable on startup. + */ + SET_CAP(CAP_DAC_READ_SEARCH); + + /* + * XXX We might want to add CAP_SYS_RESOURCE, though it's not + * clear it would work right given the way linuxthreads work. + * XXXDCL But since we need to be able to set the maximum number + * of files, the stack size, data size, and core dump size to + * support named.conf options, this is now being added to test. + */ + SET_CAP(CAP_SYS_RESOURCE); + + linux_setcaps(caps); + +#ifdef HAVE_LIBCAP + FREE_CAP; +#endif +} + +static void +linux_minprivs(void) { + cap_t caps; +#ifdef HAVE_LIBCAP + cap_t curcaps; + cap_value_t capval; + char strbuf[ISC_STRERRORSIZE]; + int err; +#endif + + INIT_CAP; + /*% + * Drop all privileges except the ability to bind() to privileged + * ports. + * + * It's important that we drop CAP_SYS_CHROOT. If we didn't, it + * chroot() could be used to escape from the chrooted area. + */ + + SET_CAP(CAP_NET_BIND_SERVICE); + + /* + * XXX We might want to add CAP_SYS_RESOURCE, though it's not + * clear it would work right given the way linuxthreads work. + * XXXDCL But since we need to be able to set the maximum number + * of files, the stack size, data size, and core dump size to + * support named.conf options, this is now being added to test. + */ + SET_CAP(CAP_SYS_RESOURCE); + + linux_setcaps(caps); + +#ifdef HAVE_LIBCAP + FREE_CAP; +#endif +} + +#ifdef HAVE_SYS_PRCTL_H +static void +linux_keepcaps(void) { + char strbuf[ISC_STRERRORSIZE]; + /*% + * Ask the kernel to allow us to keep our capabilities after we + * setuid(). + */ + + if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) { + if (errno != EINVAL) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlyfatal("prctl() failed: %s", strbuf); + } + } else { + non_root_caps = ISC_TRUE; + if (getuid() != 0) + non_root = ISC_TRUE; + } +} +#endif + +#endif /* HAVE_LINUX_CAPABILITY_H */ + + +static void +setup_syslog(const char *progname) { + int options; + + options = LOG_PID; +#ifdef LOG_NDELAY + options |= LOG_NDELAY; +#endif + openlog(isc_file_basename(progname), options, ISC_FACILITY); +} + +void +ns_os_init(const char *progname) { + setup_syslog(progname); +#ifdef HAVE_LINUX_CAPABILITY_H + linux_initialprivs(); +#endif +#ifdef HAVE_LINUXTHREADS + mainpid = getpid(); +#endif +#ifdef SIGXFSZ + signal(SIGXFSZ, SIG_IGN); +#endif +} + +void +ns_os_daemonize(void) { + pid_t pid; + char strbuf[ISC_STRERRORSIZE]; + + if (pipe(dfd) == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlyfatal("pipe(): %s", strbuf); + } + + pid = fork(); + if (pid == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlyfatal("fork(): %s", strbuf); + } + if (pid != 0) { + int n; + /* + * Wait for the child to finish loading for the first time. + * This would be so much simpler if fork() worked once we + * were multi-threaded. + */ + (void)close(dfd[1]); + do { + char buf; + n = read(dfd[0], &buf, 1); + if (n == 1) + _exit(0); + } while (n == -1 && errno == EINTR); + _exit(1); + } + (void)close(dfd[0]); + + /* + * We're the child. + */ + +#ifdef HAVE_LINUXTHREADS + mainpid = getpid(); +#endif + + if (setsid() == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlyfatal("setsid(): %s", strbuf); + } + + /* + * Try to set stdin, stdout, and stderr to /dev/null, but press + * on even if it fails. + * + * XXXMLG The close() calls here are unneeded on all but NetBSD, but + * are harmless to include everywhere. dup2() is supposed to close + * the FD if it is in use, but unproven-pthreads-0.16 is broken + * and will end up closing the wrong FD. This will be fixed eventually, + * and these calls will be removed. + */ + if (devnullfd != -1) { + if (devnullfd != STDIN_FILENO) { + (void)close(STDIN_FILENO); + (void)dup2(devnullfd, STDIN_FILENO); + } + if (devnullfd != STDOUT_FILENO) { + (void)close(STDOUT_FILENO); + (void)dup2(devnullfd, STDOUT_FILENO); + } + if (devnullfd != STDERR_FILENO) { + (void)close(STDERR_FILENO); + (void)dup2(devnullfd, STDERR_FILENO); + } + } +} + +void +ns_os_started(void) { + char buf = 0; + + /* + * Signal to the parent that we started successfully. + */ + if (dfd[0] != -1 && dfd[1] != -1) { + if (write(dfd[1], &buf, 1) != 1) + ns_main_earlyfatal("unable to signal parent that we " + "otherwise started successfully."); + close(dfd[1]); + dfd[0] = dfd[1] = -1; + } +} + +void +ns_os_opendevnull(void) { + devnullfd = open("/dev/null", O_RDWR, 0); +} + +void +ns_os_closedevnull(void) { + if (devnullfd != STDIN_FILENO && + devnullfd != STDOUT_FILENO && + devnullfd != STDERR_FILENO) { + close(devnullfd); + devnullfd = -1; + } +} + +static isc_boolean_t +all_digits(const char *s) { + if (*s == '\0') + return (ISC_FALSE); + while (*s != '\0') { + if (!isdigit((*s)&0xff)) + return (ISC_FALSE); + s++; + } + return (ISC_TRUE); +} + +void +ns_os_chroot(const char *root) { + char strbuf[ISC_STRERRORSIZE]; +#ifdef HAVE_LIBSCF + ns_smf_chroot = 0; +#endif + if (root != NULL) { +#ifdef HAVE_CHROOT + if (chroot(root) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlyfatal("chroot(): %s", strbuf); + } +#else + ns_main_earlyfatal("chroot(): disabled"); +#endif + if (chdir("/") < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlyfatal("chdir(/): %s", strbuf); + } +#ifdef HAVE_LIBSCF + /* Set ns_smf_chroot flag on successful chroot. */ + ns_smf_chroot = 1; +#endif + } +} + +void +ns_os_inituserinfo(const char *username) { + char strbuf[ISC_STRERRORSIZE]; + if (username == NULL) + return; + + if (all_digits(username)) + runas_pw = getpwuid((uid_t)atoi(username)); + else + runas_pw = getpwnam(username); + endpwent(); + + if (runas_pw == NULL) + ns_main_earlyfatal("user '%s' unknown", username); + + if (getuid() == 0) { + if (initgroups(runas_pw->pw_name, runas_pw->pw_gid) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlyfatal("initgroups(): %s", strbuf); + } + } + +} + +void +ns_os_changeuser(void) { + char strbuf[ISC_STRERRORSIZE]; + if (runas_pw == NULL || done_setuid) + return; + + done_setuid = ISC_TRUE; + +#ifdef HAVE_LINUXTHREADS +#ifdef HAVE_LINUX_CAPABILITY_H + if (!non_root_caps) + ns_main_earlyfatal("-u with Linux threads not supported: " + "requires kernel support for " + "prctl(PR_SET_KEEPCAPS)"); +#else + ns_main_earlyfatal("-u with Linux threads not supported: " + "no capabilities support or capabilities " + "disabled at build time"); +#endif +#endif + + if (setgid(runas_pw->pw_gid) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlyfatal("setgid(): %s", strbuf); + } + + if (setuid(runas_pw->pw_uid) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlyfatal("setuid(): %s", strbuf); + } + +#if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_DUMPABLE) + /* + * Restore the ability of named to drop core after the setuid() + * call has disabled it. + */ + if (prctl(PR_SET_DUMPABLE,1,0,0,0) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlywarning("prctl(PR_SET_DUMPABLE) failed: %s", + strbuf); + } +#endif +#if defined(HAVE_LINUX_CAPABILITY_H) && !defined(HAVE_LINUXTHREADS) + linux_minprivs(); +#endif +} + +void +ns_os_adjustnofile() { +#ifdef HAVE_LINUXTHREADS + isc_result_t result; + isc_resourcevalue_t newvalue; + + /* + * Linux: max number of open files specified by one thread doesn't seem + * to apply to other threads on Linux. + */ + newvalue = ISC_RESOURCE_UNLIMITED; + + result = isc_resource_setlimit(isc_resource_openfiles, newvalue); + if (result != ISC_R_SUCCESS) + ns_main_earlywarning("couldn't adjust limit on open files"); +#endif +} + +void +ns_os_minprivs(void) { +#ifdef HAVE_SYS_PRCTL_H + linux_keepcaps(); +#endif + +#ifdef HAVE_LINUXTHREADS + ns_os_changeuser(); /* Call setuid() before threads are started */ +#endif + +#if defined(HAVE_LINUX_CAPABILITY_H) && defined(HAVE_LINUXTHREADS) + linux_minprivs(); +#endif +} + +static int +safe_open(const char *filename, isc_boolean_t append) { + int fd; + struct stat sb; + + if (stat(filename, &sb) == -1) { + if (errno != ENOENT) + return (-1); + } else if ((sb.st_mode & S_IFREG) == 0) { + errno = EOPNOTSUPP; + return (-1); + } + + if (append) + fd = open(filename, O_WRONLY|O_CREAT|O_APPEND, + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + else { + if (unlink(filename) < 0 && errno != ENOENT) + return (-1); + fd = open(filename, O_WRONLY|O_CREAT|O_EXCL, + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + } + return (fd); +} + +static void +cleanup_pidfile(void) { + int n; + if (pidfile != NULL) { + n = unlink(pidfile); + if (n == -1 && errno != ENOENT) + ns_main_earlywarning("unlink '%s': failed", pidfile); + free(pidfile); + } + pidfile = NULL; +} + +void +ns_os_writepidfile(const char *filename, isc_boolean_t first_time) { + int fd; + FILE *lockfile; + size_t len; + pid_t pid; + char strbuf[ISC_STRERRORSIZE]; + void (*report)(const char *, ...); + + /* + * The caller must ensure any required synchronization. + */ + + report = first_time ? ns_main_earlyfatal : ns_main_earlywarning; + + cleanup_pidfile(); + + if (filename == NULL) + return; + + len = strlen(filename); + pidfile = malloc(len + 1); + if (pidfile == NULL) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + (*report)("couldn't malloc '%s': %s", filename, strbuf); + return; + } + /* This is safe. */ + strcpy(pidfile, filename); + + fd = safe_open(filename, ISC_FALSE); + if (fd < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + (*report)("couldn't open pid file '%s': %s", filename, strbuf); + free(pidfile); + pidfile = NULL; + return; + } + lockfile = fdopen(fd, "w"); + if (lockfile == NULL) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + (*report)("could not fdopen() pid file '%s': %s", + filename, strbuf); + (void)close(fd); + cleanup_pidfile(); + return; + } +#ifdef HAVE_LINUXTHREADS + pid = mainpid; +#else + pid = getpid(); +#endif + if (fprintf(lockfile, "%ld\n", (long)pid) < 0) { + (*report)("fprintf() to pid file '%s' failed", filename); + (void)fclose(lockfile); + cleanup_pidfile(); + return; + } + if (fflush(lockfile) == EOF) { + (*report)("fflush() to pid file '%s' failed", filename); + (void)fclose(lockfile); + cleanup_pidfile(); + return; + } + (void)fclose(lockfile); +} + +void +ns_os_shutdown(void) { + closelog(); + cleanup_pidfile(); +} + +isc_result_t +ns_os_gethostname(char *buf, size_t len) { + int n; + + n = gethostname(buf, len); + return ((n == 0) ? ISC_R_SUCCESS : ISC_R_FAILURE); +} + +static char * +next_token(char **stringp, const char *delim) { + char *res; + + do { + res = strsep(stringp, delim); + if (res == NULL) + break; + } while (*res == '\0'); + return (res); +} + +void +ns_os_shutdownmsg(char *command, isc_buffer_t *text) { + char *input, *ptr; + unsigned int n; + pid_t pid; + + input = command; + + /* Skip the command name. */ + ptr = next_token(&input, " \t"); + if (ptr == NULL) + return; + + ptr = next_token(&input, " \t"); + if (ptr == NULL) + return; + + if (strcmp(ptr, "-p") != 0) + return; + +#ifdef HAVE_LINUXTHREADS + pid = mainpid; +#else + pid = getpid(); +#endif + + n = snprintf((char *)isc_buffer_used(text), + isc_buffer_availablelength(text), + "pid: %ld", (long)pid); + /* Only send a message if it is complete. */ + if (n < isc_buffer_availablelength(text)) + isc_buffer_add(text, n); +} + +void +ns_os_tzset(void) { +#ifdef HAVE_TZSET + tzset(); +#endif +} diff --git a/contrib/bind-9.5.2/bin/named/update.c b/contrib/bind-9.5.2/bin/named/update.c new file mode 100644 index 0000000000..d1ca0997bd --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/update.c @@ -0,0 +1,3258 @@ +/* + * Copyright (C) 2004-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 + * 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: update.c,v 1.138.2.13 2009/07/28 15:54:31 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 + +/*! \file + * \brief + * This module implements dynamic update as in RFC2136. + */ + +/* + * XXX TODO: + * - document strict minimality + */ + +/**************************************************************************/ + +/*% + * Log level for tracing dynamic update protocol requests. + */ +#define LOGLEVEL_PROTOCOL ISC_LOG_INFO + +/*% + * Log level for low-level debug tracing. + */ +#define LOGLEVEL_DEBUG ISC_LOG_DEBUG(8) + +/*% + * Check an operation for failure. These macros all assume that + * the function using them has a 'result' variable and a 'failure' + * label. + */ +#define CHECK(op) \ + do { result = (op); \ + if (result != ISC_R_SUCCESS) goto failure; \ + } while (0) + +/*% + * Fail unconditionally with result 'code', which must not + * be ISC_R_SUCCESS. The reason for failure presumably has + * been logged already. + * + * The test against ISC_R_SUCCESS is there to keep the Solaris compiler + * from complaining about "end-of-loop code not reached". + */ + +#define FAIL(code) \ + do { \ + result = (code); \ + if (result != ISC_R_SUCCESS) goto failure; \ + } while (0) + +/*% + * Fail unconditionally and log as a client error. + * The test against ISC_R_SUCCESS is there to keep the Solaris compiler + * from complaining about "end-of-loop code not reached". + */ +#define FAILC(code, msg) \ + do { \ + const char *_what = "failed"; \ + result = (code); \ + switch (result) { \ + case DNS_R_NXDOMAIN: \ + case DNS_R_YXDOMAIN: \ + case DNS_R_YXRRSET: \ + case DNS_R_NXRRSET: \ + _what = "unsuccessful"; \ + } \ + update_log(client, zone, LOGLEVEL_PROTOCOL, \ + "update %s: %s (%s)", _what, \ + msg, isc_result_totext(result)); \ + if (result != ISC_R_SUCCESS) goto failure; \ + } while (0) +#define PREREQFAILC(code, msg) \ + do { \ + inc_stats(zone, dns_nsstatscounter_updatebadprereq); \ + FAILC(code, msg); \ + } while (0) + +#define FAILN(code, name, msg) \ + do { \ + const char *_what = "failed"; \ + result = (code); \ + switch (result) { \ + case DNS_R_NXDOMAIN: \ + case DNS_R_YXDOMAIN: \ + case DNS_R_YXRRSET: \ + case DNS_R_NXRRSET: \ + _what = "unsuccessful"; \ + } \ + if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) { \ + char _nbuf[DNS_NAME_FORMATSIZE]; \ + dns_name_format(name, _nbuf, sizeof(_nbuf)); \ + update_log(client, zone, LOGLEVEL_PROTOCOL, \ + "update %s: %s: %s (%s)", _what, _nbuf, \ + msg, isc_result_totext(result)); \ + } \ + if (result != ISC_R_SUCCESS) goto failure; \ + } while (0) +#define PREREQFAILN(code, name, msg) \ + do { \ + inc_stats(zone, dns_nsstatscounter_updatebadprereq); \ + FAILN(code, name, msg); \ + } while (0) + +#define FAILNT(code, name, type, msg) \ + do { \ + const char *_what = "failed"; \ + result = (code); \ + switch (result) { \ + case DNS_R_NXDOMAIN: \ + case DNS_R_YXDOMAIN: \ + case DNS_R_YXRRSET: \ + case DNS_R_NXRRSET: \ + _what = "unsuccessful"; \ + } \ + if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) { \ + char _nbuf[DNS_NAME_FORMATSIZE]; \ + char _tbuf[DNS_RDATATYPE_FORMATSIZE]; \ + dns_name_format(name, _nbuf, sizeof(_nbuf)); \ + dns_rdatatype_format(type, _tbuf, sizeof(_tbuf)); \ + update_log(client, zone, LOGLEVEL_PROTOCOL, \ + "update %s: %s/%s: %s (%s)", \ + _what, _nbuf, _tbuf, msg, \ + isc_result_totext(result)); \ + } \ + if (result != ISC_R_SUCCESS) goto failure; \ + } while (0) +#define PREREQFAILNT(code, name, type, msg) \ + do { \ + inc_stats(zone, dns_nsstatscounter_updatebadprereq); \ + FAILNT(code, name, type, msg); \ + } while (0) + +/*% + * Fail unconditionally and log as a server error. + * The test against ISC_R_SUCCESS is there to keep the Solaris compiler + * from complaining about "end-of-loop code not reached". + */ +#define FAILS(code, msg) \ + do { \ + result = (code); \ + update_log(client, zone, LOGLEVEL_PROTOCOL, \ + "error: %s: %s", \ + msg, isc_result_totext(result)); \ + if (result != ISC_R_SUCCESS) goto failure; \ + } while (0) + +/**************************************************************************/ + +typedef struct rr rr_t; + +struct rr { + /* dns_name_t name; */ + isc_uint32_t ttl; + dns_rdata_t rdata; +}; + +typedef struct update_event update_event_t; + +struct update_event { + ISC_EVENT_COMMON(update_event_t); + dns_zone_t *zone; + isc_result_t result; + dns_message_t *answer; +}; + +/**************************************************************************/ +/* + * Forward declarations. + */ + +static void update_action(isc_task_t *task, isc_event_t *event); +static void updatedone_action(isc_task_t *task, isc_event_t *event); +static isc_result_t send_forward_event(ns_client_t *client, dns_zone_t *zone); +static void forward_done(isc_task_t *task, isc_event_t *event); + +/**************************************************************************/ + +static void +update_log(ns_client_t *client, dns_zone_t *zone, + int level, const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5); + +static void +update_log(ns_client_t *client, dns_zone_t *zone, + int level, const char *fmt, ...) +{ + va_list ap; + char message[4096]; + char namebuf[DNS_NAME_FORMATSIZE]; + char classbuf[DNS_RDATACLASS_FORMATSIZE]; + + if (client == NULL || zone == NULL) + return; + + if (isc_log_wouldlog(ns_g_lctx, level) == ISC_FALSE) + return; + + dns_name_format(dns_zone_getorigin(zone), namebuf, + sizeof(namebuf)); + dns_rdataclass_format(dns_zone_getclass(zone), classbuf, + sizeof(classbuf)); + + va_start(ap, fmt); + vsnprintf(message, sizeof(message), fmt, ap); + va_end(ap); + + ns_client_log(client, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE, + level, "updating zone '%s/%s': %s", + namebuf, classbuf, message); +} + +/*% + * Increment updated-related statistics counters. + */ +static inline void +inc_stats(dns_zone_t *zone, isc_statscounter_t counter) { + isc_stats_increment(ns_g_server->nsstats, counter); + + if (zone != NULL) { + isc_stats_t *zonestats = dns_zone_getrequeststats(zone); + if (zonestats != NULL) + isc_stats_increment(zonestats, counter); + } +} + +/*% + * Override the default acl logging when checking whether a client + * can update the zone or whether we can forward the request to the + * master based on IP address. + * + * 'message' contains the type of operation that is being attempted. + * 'slave' indicates if this is a slave zone. If 'acl' is NULL then + * log at debug=3. + * If the zone has no access controls configured ('acl' == NULL && + * 'has_ssutable == ISC_FALS) log the attempt at info, otherwise + * at error. + * + * If the request was signed log that we received it. + */ +static isc_result_t +checkupdateacl(ns_client_t *client, dns_acl_t *acl, const char *message, + dns_name_t *zonename, isc_boolean_t slave, + isc_boolean_t has_ssutable) +{ + char namebuf[DNS_NAME_FORMATSIZE]; + char classbuf[DNS_RDATACLASS_FORMATSIZE]; + int level = ISC_LOG_ERROR; + const char *msg = "denied"; + isc_result_t result; + + if (slave && acl == NULL) { + result = DNS_R_NOTIMP; + level = ISC_LOG_DEBUG(3); + msg = "disabled"; + } else { + result = ns_client_checkaclsilent(client, NULL, acl, ISC_FALSE); + if (result == ISC_R_SUCCESS) { + level = ISC_LOG_DEBUG(3); + msg = "approved"; + } else if (acl == NULL && !has_ssutable) { + level = ISC_LOG_INFO; + } + } + + if (client->signer != NULL) { + dns_name_format(client->signer, namebuf, sizeof(namebuf)); + ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY, + NS_LOGMODULE_UPDATE, ISC_LOG_INFO, + "signer \"%s\" %s", namebuf, msg); + } + + dns_name_format(zonename, namebuf, sizeof(namebuf)); + dns_rdataclass_format(client->view->rdclass, classbuf, + sizeof(classbuf)); + + ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY, + NS_LOGMODULE_UPDATE, level, "%s '%s/%s' %s", + message, namebuf, classbuf, msg); + return (result); +} + +/*% + * Update a single RR in version 'ver' of 'db' and log the + * update in 'diff'. + * + * Ensures: + * \li '*tuple' == NULL. Either the tuple is freed, or its + * ownership has been transferred to the diff. + */ +static isc_result_t +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; + + /* + * Create a singleton diff. + */ + dns_diff_init(diff->mctx, &temp_diff); + 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); + if (result != ISC_R_SUCCESS) { + dns_difftuple_free(tuple); + return (result); + } + + /* + * Merge it into the current pending journal entry. + */ + dns_diff_appendminimal(diff, tuple); + + /* + * Do not clear temp_diff. + */ + return (ISC_R_SUCCESS); +} + +/*% + * Perform the updates in 'updates' in version 'ver' of 'db' and log the + * update in 'diff'. + * + * Ensures: + * \li 'updates' is empty. + */ +static isc_result_t +do_diff(dns_diff_t *updates, dns_db_t *db, dns_dbversion_t *ver, + dns_diff_t *diff) +{ + isc_result_t result; + while (! ISC_LIST_EMPTY(updates->tuples)) { + dns_difftuple_t *t = ISC_LIST_HEAD(updates->tuples); + ISC_LIST_UNLINK(updates->tuples, t, link); + CHECK(do_one_tuple(&t, db, ver, diff)); + } + return (ISC_R_SUCCESS); + + failure: + dns_diff_clear(diff); + return (result); +} + +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) +{ + 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)); +} + +/**************************************************************************/ +/* + * Callback-style iteration over rdatasets and rdatas. + * + * foreach_rrset() can be used to iterate over the RRsets + * of a name and call a callback function with each + * one. Similarly, foreach_rr() can be used to iterate + * over the individual RRs at name, optionally restricted + * to RRs of a given type. + * + * The callback functions are called "actions" and take + * two arguments: a void pointer for passing arbitrary + * context information, and a pointer to the current RRset + * or RR. By convention, their names end in "_action". + */ + +/* + * XXXRTH We might want to make this public somewhere in libdns. + */ + +/*% + * Function type for foreach_rrset() iterator actions. + */ +typedef isc_result_t rrset_func(void *data, dns_rdataset_t *rrset); + +/*% + * Function type for foreach_rr() iterator actions. + */ +typedef isc_result_t rr_func(void *data, rr_t *rr); + +/*% + * Internal context struct for foreach_node_rr(). + */ +typedef struct { + rr_func * rr_action; + void * rr_action_data; +} foreach_node_rr_ctx_t; + +/*% + * Internal helper function for foreach_node_rr(). + */ +static isc_result_t +foreach_node_rr_action(void *data, dns_rdataset_t *rdataset) { + isc_result_t result; + foreach_node_rr_ctx_t *ctx = data; + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) + { + rr_t rr = { 0, DNS_RDATA_INIT }; + + dns_rdataset_current(rdataset, &rr.rdata); + rr.ttl = rdataset->ttl; + result = (*ctx->rr_action)(ctx->rr_action_data, &rr); + if (result != ISC_R_SUCCESS) + return (result); + } + if (result != ISC_R_NOMORE) + return (result); + return (ISC_R_SUCCESS); +} + +/*% + * For each rdataset of 'name' in 'ver' of 'db', call 'action' + * with the rdataset and 'action_data' as arguments. If the name + * does not exist, do nothing. + * + * If 'action' returns an error, abort iteration and return the error. + */ +static isc_result_t +foreach_rrset(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, + rrset_func *action, void *action_data) +{ + isc_result_t result; + dns_dbnode_t *node; + dns_rdatasetiter_t *iter; + + node = NULL; + result = dns_db_findnode(db, name, ISC_FALSE, &node); + if (result == ISC_R_NOTFOUND) + return (ISC_R_SUCCESS); + if (result != ISC_R_SUCCESS) + return (result); + + iter = NULL; + result = dns_db_allrdatasets(db, node, ver, + (isc_stdtime_t) 0, &iter); + if (result != ISC_R_SUCCESS) + goto cleanup_node; + + for (result = dns_rdatasetiter_first(iter); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(iter)) + { + dns_rdataset_t rdataset; + + dns_rdataset_init(&rdataset); + dns_rdatasetiter_current(iter, &rdataset); + + result = (*action)(action_data, &rdataset); + + dns_rdataset_disassociate(&rdataset); + if (result != ISC_R_SUCCESS) + goto cleanup_iterator; + } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + + cleanup_iterator: + dns_rdatasetiter_destroy(&iter); + + cleanup_node: + dns_db_detachnode(db, &node); + + return (result); +} + +/*% + * For each RR of 'name' in 'ver' of 'db', call 'action' + * with the RR and 'action_data' as arguments. If the name + * does not exist, do nothing. + * + * If 'action' returns an error, abort iteration + * and return the error. + */ +static isc_result_t +foreach_node_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, + rr_func *rr_action, void *rr_action_data) +{ + foreach_node_rr_ctx_t ctx; + ctx.rr_action = rr_action; + ctx.rr_action_data = rr_action_data; + return (foreach_rrset(db, ver, name, + foreach_node_rr_action, &ctx)); +} + + +/*% + * For each of the RRs specified by 'db', 'ver', 'name', 'type', + * (which can be dns_rdatatype_any to match any type), and 'covers', call + * 'action' with the RR and 'action_data' as arguments. If the name + * does not exist, or if no RRset of the given type exists at the name, + * do nothing. + * + * If 'action' returns an error, abort iteration and return the error. + */ +static isc_result_t +foreach_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, + dns_rdatatype_t type, dns_rdatatype_t covers, rr_func *rr_action, + void *rr_action_data) +{ + + isc_result_t result; + dns_dbnode_t *node; + dns_rdataset_t rdataset; + + if (type == dns_rdatatype_any) + return (foreach_node_rr(db, ver, name, + rr_action, rr_action_data)); + + node = NULL; + result = dns_db_findnode(db, name, ISC_FALSE, &node); + if (result == ISC_R_NOTFOUND) + return (ISC_R_SUCCESS); + if (result != ISC_R_SUCCESS) + return (result); + + dns_rdataset_init(&rdataset); + result = dns_db_findrdataset(db, node, ver, type, covers, + (isc_stdtime_t) 0, &rdataset, NULL); + if (result == ISC_R_NOTFOUND) { + result = ISC_R_SUCCESS; + goto cleanup_node; + } + if (result != ISC_R_SUCCESS) + goto cleanup_node; + + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) + { + rr_t rr = { 0, DNS_RDATA_INIT }; + dns_rdataset_current(&rdataset, &rr.rdata); + rr.ttl = rdataset.ttl; + result = (*rr_action)(rr_action_data, &rr); + if (result != ISC_R_SUCCESS) + goto cleanup_rdataset; + } + if (result != ISC_R_NOMORE) + goto cleanup_rdataset; + result = ISC_R_SUCCESS; + + cleanup_rdataset: + dns_rdataset_disassociate(&rdataset); + cleanup_node: + dns_db_detachnode(db, &node); + + return (result); +} + +/**************************************************************************/ +/* + * Various tests on the database contents (for prerequisites, etc). + */ + +/*% + * Function type for predicate functions that compare a database RR 'db_rr' + * against an update RR 'update_rr'. + */ +typedef isc_boolean_t rr_predicate(dns_rdata_t *update_rr, dns_rdata_t *db_rr); + +/*% + * Helper function for rrset_exists(). + */ +static isc_result_t +rrset_exists_action(void *data, rr_t *rr) { + UNUSED(data); + UNUSED(rr); + return (ISC_R_EXISTS); +} + +/*% + * Utility macro for RR existence checking functions. + * + * If the variable 'result' has the value ISC_R_EXISTS or + * ISC_R_SUCCESS, set *exists to ISC_TRUE or ISC_FALSE, + * respectively, and return success. + * + * If 'result' has any other value, there was a failure. + * Return the failure result code and do not set *exists. + * + * This would be more readable as "do { if ... } while(0)", + * but that form generates tons of warnings on Solaris 2.6. + */ +#define RETURN_EXISTENCE_FLAG \ + return ((result == ISC_R_EXISTS) ? \ + (*exists = ISC_TRUE, ISC_R_SUCCESS) : \ + ((result == ISC_R_SUCCESS) ? \ + (*exists = ISC_FALSE, ISC_R_SUCCESS) : \ + result)) + +/*% + * Set '*exists' to true iff an rrset of the given type exists, + * to false otherwise. + */ +static isc_result_t +rrset_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, + dns_rdatatype_t type, dns_rdatatype_t covers, + isc_boolean_t *exists) +{ + isc_result_t result; + result = foreach_rr(db, ver, name, type, covers, + rrset_exists_action, NULL); + RETURN_EXISTENCE_FLAG; +} + +/*% + * Set '*visible' to true if the RRset exists and is part of the + * visible zone. Otherwise '*visible' is set to false unless a + * error occurs. + */ +static isc_result_t +rrset_visible(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, + dns_rdatatype_t type, isc_boolean_t *visible) +{ + isc_result_t result; + dns_fixedname_t fixed; + + dns_fixedname_init(&fixed); + result = dns_db_find(db, name, ver, type, DNS_DBFIND_NOWILD, + (isc_stdtime_t) 0, NULL, + dns_fixedname_name(&fixed), NULL, NULL); + switch (result) { + case ISC_R_SUCCESS: + *visible = ISC_TRUE; + break; + /* + * Glue, obscured, deleted or replaced records. + */ + case DNS_R_DELEGATION: + case DNS_R_DNAME: + case DNS_R_CNAME: + case DNS_R_NXDOMAIN: + case DNS_R_NXRRSET: + case DNS_R_EMPTYNAME: + case DNS_R_COVERINGNSEC: + *visible = ISC_FALSE; + result = ISC_R_SUCCESS; + break; + default: + break; + } + return (result); +} + +/*% + * Helper function for cname_incompatible_rrset_exists. + */ +static isc_result_t +cname_compatibility_action(void *data, dns_rdataset_t *rrset) { + UNUSED(data); + if (rrset->type != dns_rdatatype_cname && + ! dns_rdatatype_isdnssec(rrset->type)) + return (ISC_R_EXISTS); + return (ISC_R_SUCCESS); +} + +/*% + * Check whether there is an rrset incompatible with adding a CNAME RR, + * i.e., anything but another CNAME (which can be replaced) or a + * DNSSEC RR (which can coexist). + * + * If such an incompatible rrset exists, set '*exists' to ISC_TRUE. + * Otherwise, set it to ISC_FALSE. + */ +static isc_result_t +cname_incompatible_rrset_exists(dns_db_t *db, dns_dbversion_t *ver, + dns_name_t *name, isc_boolean_t *exists) { + isc_result_t result; + result = foreach_rrset(db, ver, name, + cname_compatibility_action, NULL); + RETURN_EXISTENCE_FLAG; +} + +/*% + * Helper function for rr_count(). + */ +static isc_result_t +count_rr_action(void *data, rr_t *rr) { + int *countp = data; + UNUSED(rr); + (*countp)++; + return (ISC_R_SUCCESS); +} + +/*% + * Count the number of RRs of 'type' belonging to 'name' in 'ver' of 'db'. + */ +static isc_result_t +rr_count(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, + dns_rdatatype_t type, dns_rdatatype_t covers, int *countp) +{ + *countp = 0; + return (foreach_rr(db, ver, name, type, covers, + count_rr_action, countp)); +} + +/*% + * Context struct and helper function for name_exists(). + */ + +static isc_result_t +name_exists_action(void *data, dns_rdataset_t *rrset) { + UNUSED(data); + UNUSED(rrset); + return (ISC_R_EXISTS); +} + +/*% + * Set '*exists' to true iff the given name exists, to false otherwise. + */ +static isc_result_t +name_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, + isc_boolean_t *exists) +{ + isc_result_t result; + result = foreach_rrset(db, ver, name, + name_exists_action, NULL); + RETURN_EXISTENCE_FLAG; +} + +typedef struct { + dns_name_t *name; + dns_name_t *signer; + dns_ssutable_t *table; +} ssu_check_t; + +static isc_result_t +ssu_checkrule(void *data, dns_rdataset_t *rrset) { + ssu_check_t *ssuinfo = data; + isc_boolean_t result; + + /* + * If we're deleting all records, it's ok to delete RRSIG and NSEC even + * if we're normally not allowed to. + */ + if (rrset->type == dns_rdatatype_rrsig || + rrset->type == dns_rdatatype_nsec) + return (ISC_R_SUCCESS); + result = dns_ssutable_checkrules(ssuinfo->table, ssuinfo->signer, + ssuinfo->name, rrset->type); + return (result == ISC_TRUE ? ISC_R_SUCCESS : ISC_R_FAILURE); +} + +static isc_boolean_t +ssu_checkall(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, + dns_ssutable_t *ssutable, dns_name_t *signer) +{ + isc_result_t result; + ssu_check_t ssuinfo; + + ssuinfo.name = name; + ssuinfo.table = ssutable; + ssuinfo.signer = signer; + result = foreach_rrset(db, ver, name, ssu_checkrule, &ssuinfo); + return (ISC_TF(result == ISC_R_SUCCESS)); +} + +/**************************************************************************/ +/* + * Checking of "RRset exists (value dependent)" prerequisites. + * + * In the RFC2136 section 3.2.5, this is the pseudocode involving + * a variable called "temp", a mapping of tuples to rrsets. + * + * Here, we represent the "temp" data structure as (non-minimal) "dns_diff_t" + * where each tuple has op==DNS_DIFFOP_EXISTS. + */ + + +/*% + * Append a tuple asserting the existence of the RR with + * 'name' and 'rdata' to 'diff'. + */ +static isc_result_t +temp_append(dns_diff_t *diff, dns_name_t *name, dns_rdata_t *rdata) { + isc_result_t result; + dns_difftuple_t *tuple = NULL; + + REQUIRE(DNS_DIFF_VALID(diff)); + CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_EXISTS, + name, 0, rdata, &tuple)); + ISC_LIST_APPEND(diff->tuples, tuple, link); + failure: + return (result); +} + +/*% + * Compare two rdatasets represented as sorted lists of tuples. + * All list elements must have the same owner name and type. + * Return ISC_R_SUCCESS if the rdatasets are equal, rcode(dns_rcode_nxrrset) + * if not. + */ +static isc_result_t +temp_check_rrset(dns_difftuple_t *a, dns_difftuple_t *b) { + for (;;) { + if (a == NULL || b == NULL) + break; + INSIST(a->op == DNS_DIFFOP_EXISTS && + b->op == DNS_DIFFOP_EXISTS); + INSIST(a->rdata.type == b->rdata.type); + INSIST(dns_name_equal(&a->name, &b->name)); + if (dns_rdata_compare(&a->rdata, &b->rdata) != 0) + return (DNS_R_NXRRSET); + a = ISC_LIST_NEXT(a, link); + b = ISC_LIST_NEXT(b, link); + } + if (a != NULL || b != NULL) + return (DNS_R_NXRRSET); + return (ISC_R_SUCCESS); +} + +/*% + * A comparison function defining the sorting order for the entries + * in the "temp" data structure. The major sort key is the owner name, + * followed by the type and rdata. + */ +static int +temp_order(const void *av, const void *bv) { + dns_difftuple_t const * const *ap = av; + dns_difftuple_t const * const *bp = bv; + dns_difftuple_t const *a = *ap; + dns_difftuple_t const *b = *bp; + int r; + r = dns_name_compare(&a->name, &b->name); + if (r != 0) + return (r); + r = (b->rdata.type - a->rdata.type); + if (r != 0) + return (r); + r = dns_rdata_compare(&a->rdata, &b->rdata); + return (r); +} + +/*% + * Check the "RRset exists (value dependent)" prerequisite information + * in 'temp' against the contents of the database 'db'. + * + * Return ISC_R_SUCCESS if the prerequisites are satisfied, + * rcode(dns_rcode_nxrrset) if not. + * + * 'temp' must be pre-sorted. + */ + +static isc_result_t +temp_check(isc_mem_t *mctx, dns_diff_t *temp, dns_db_t *db, + dns_dbversion_t *ver, dns_name_t *tmpname, dns_rdatatype_t *typep) +{ + isc_result_t result; + dns_name_t *name; + dns_dbnode_t *node; + dns_difftuple_t *t; + dns_diff_t trash; + + dns_diff_init(mctx, &trash); + + /* + * For each name and type in the prerequisites, + * construct a sorted rdata list of the corresponding + * database contents, and compare the lists. + */ + t = ISC_LIST_HEAD(temp->tuples); + while (t != NULL) { + name = &t->name; + (void)dns_name_copy(name, tmpname, NULL); + *typep = t->rdata.type; + + /* A new unique name begins here. */ + node = NULL; + result = dns_db_findnode(db, name, ISC_FALSE, &node); + if (result == ISC_R_NOTFOUND) { + dns_diff_clear(&trash); + return (DNS_R_NXRRSET); + } + if (result != ISC_R_SUCCESS) { + dns_diff_clear(&trash); + return (result); + } + + /* A new unique type begins here. */ + while (t != NULL && dns_name_equal(&t->name, name)) { + dns_rdatatype_t type, covers; + dns_rdataset_t rdataset; + dns_diff_t d_rrs; /* Database RRs with + this name and type */ + dns_diff_t u_rrs; /* Update RRs with + this name and type */ + + *typep = type = t->rdata.type; + if (type == dns_rdatatype_rrsig || + type == dns_rdatatype_sig) + covers = dns_rdata_covers(&t->rdata); + else if (type == dns_rdatatype_any) { + dns_db_detachnode(db, &node); + dns_diff_clear(&trash); + return (DNS_R_NXRRSET); + } else + covers = 0; + + /* + * Collect all database RRs for this name and type + * onto d_rrs and sort them. + */ + dns_rdataset_init(&rdataset); + result = dns_db_findrdataset(db, node, ver, type, + covers, (isc_stdtime_t) 0, + &rdataset, NULL); + if (result != ISC_R_SUCCESS) { + dns_db_detachnode(db, &node); + dns_diff_clear(&trash); + return (DNS_R_NXRRSET); + } + + dns_diff_init(mctx, &d_rrs); + dns_diff_init(mctx, &u_rrs); + + 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 = temp_append(&d_rrs, name, &rdata); + if (result != ISC_R_SUCCESS) + goto failure; + } + if (result != ISC_R_NOMORE) + goto failure; + result = dns_diff_sort(&d_rrs, temp_order); + if (result != ISC_R_SUCCESS) + goto failure; + + /* + * Collect all update RRs for this name and type + * onto u_rrs. No need to sort them here - + * they are already sorted. + */ + while (t != NULL && + dns_name_equal(&t->name, name) && + t->rdata.type == type) + { + dns_difftuple_t *next = + ISC_LIST_NEXT(t, link); + ISC_LIST_UNLINK(temp->tuples, t, link); + ISC_LIST_APPEND(u_rrs.tuples, t, link); + t = next; + } + + /* Compare the two sorted lists. */ + result = temp_check_rrset(ISC_LIST_HEAD(u_rrs.tuples), + ISC_LIST_HEAD(d_rrs.tuples)); + if (result != ISC_R_SUCCESS) + goto failure; + + /* + * We are done with the tuples, but we can't free + * them yet because "name" still points into one + * of them. Move them on a temporary list. + */ + ISC_LIST_APPENDLIST(trash.tuples, u_rrs.tuples, link); + ISC_LIST_APPENDLIST(trash.tuples, d_rrs.tuples, link); + dns_rdataset_disassociate(&rdataset); + + continue; + + failure: + dns_diff_clear(&d_rrs); + dns_diff_clear(&u_rrs); + dns_diff_clear(&trash); + dns_rdataset_disassociate(&rdataset); + dns_db_detachnode(db, &node); + return (result); + } + + dns_db_detachnode(db, &node); + } + + dns_diff_clear(&trash); + return (ISC_R_SUCCESS); +} + +/**************************************************************************/ +/* + * Conditional deletion of RRs. + */ + +/*% + * Context structure for delete_if(). + */ + +typedef struct { + rr_predicate *predicate; + dns_db_t *db; + dns_dbversion_t *ver; + dns_diff_t *diff; + dns_name_t *name; + dns_rdata_t *update_rr; +} conditional_delete_ctx_t; + +/*% + * Predicate functions for delete_if(). + */ + +/*% + * Return true iff 'db_rr' is neither a SOA nor an NS RR nor + * an RRSIG nor a NSEC. + */ +static isc_boolean_t +type_not_soa_nor_ns_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { + UNUSED(update_rr); + return ((db_rr->type != dns_rdatatype_soa && + db_rr->type != dns_rdatatype_ns && + db_rr->type != dns_rdatatype_rrsig && + db_rr->type != dns_rdatatype_nsec) ? + ISC_TRUE : ISC_FALSE); +} + +/*% + * Return true iff 'db_rr' is neither a RRSIG nor a NSEC. + */ +static isc_boolean_t +type_not_dnssec(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { + UNUSED(update_rr); + return ((db_rr->type != dns_rdatatype_rrsig && + db_rr->type != dns_rdatatype_nsec) ? + ISC_TRUE : ISC_FALSE); +} + +/*% + * Return true always. + */ +static isc_boolean_t +true_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { + UNUSED(update_rr); + UNUSED(db_rr); + return (ISC_TRUE); +} + +/*% + * Return true if the record is a RRSIG. + */ +static isc_boolean_t +rrsig_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { + UNUSED(update_rr); + return ((db_rr->type == dns_rdatatype_rrsig) ? + ISC_TRUE : ISC_FALSE); +} + +/*% + * Return true iff the two RRs have identical rdata. + */ +static isc_boolean_t +rr_equal_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { + /* + * XXXRTH This is not a problem, but we should consider creating + * dns_rdata_equal() (that used dns_name_equal()), since it + * would be faster. Not a priority. + */ + return (dns_rdata_compare(update_rr, db_rr) == 0 ? + ISC_TRUE : ISC_FALSE); +} + +/*% + * Return true iff 'update_rr' should replace 'db_rr' according + * to the special RFC2136 rules for CNAME, SOA, and WKS records. + * + * RFC2136 does not mention NSEC or DNAME, but multiple NSECs or DNAMEs + * make little sense, so we replace those, too. + */ +static isc_boolean_t +replaces_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { + if (db_rr->type != update_rr->type) + return (ISC_FALSE); + if (db_rr->type == dns_rdatatype_cname) + return (ISC_TRUE); + if (db_rr->type == dns_rdatatype_dname) + return (ISC_TRUE); + if (db_rr->type == dns_rdatatype_soa) + return (ISC_TRUE); + if (db_rr->type == dns_rdatatype_nsec) + return (ISC_TRUE); + if (db_rr->type == dns_rdatatype_wks) { + /* + * Compare the address and protocol fields only. These + * form the first five bytes of the RR data. Do a + * raw binary comparison; unpacking the WKS RRs using + * dns_rdata_tostruct() might be cleaner in some ways, + * but it would require us to pass around an mctx. + */ + INSIST(db_rr->length >= 5 && update_rr->length >= 5); + return (memcmp(db_rr->data, update_rr->data, 5) == 0 ? + ISC_TRUE : ISC_FALSE); + } + return (ISC_FALSE); +} + +/*% + * Internal helper function for delete_if(). + */ +static isc_result_t +delete_if_action(void *data, rr_t *rr) { + conditional_delete_ctx_t *ctx = data; + if ((*ctx->predicate)(ctx->update_rr, &rr->rdata)) { + isc_result_t result; + result = update_one_rr(ctx->db, ctx->ver, ctx->diff, + DNS_DIFFOP_DEL, ctx->name, + rr->ttl, &rr->rdata); + return (result); + } else { + return (ISC_R_SUCCESS); + } +} + +/*% + * Conditionally delete RRs. Apply 'predicate' to the RRs + * specified by 'db', 'ver', 'name', and 'type' (which can + * be dns_rdatatype_any to match any type). Delete those + * RRs for which the predicate returns true, and log the + * deletions in 'diff'. + */ +static isc_result_t +delete_if(rr_predicate *predicate, dns_db_t *db, dns_dbversion_t *ver, + dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers, + dns_rdata_t *update_rr, dns_diff_t *diff) +{ + conditional_delete_ctx_t ctx; + ctx.predicate = predicate; + ctx.db = db; + ctx.ver = ver; + ctx.diff = diff; + ctx.name = name; + ctx.update_rr = update_rr; + return (foreach_rr(db, ver, name, type, covers, + delete_if_action, &ctx)); +} + +/**************************************************************************/ +/*% + * Prepare an RR for the addition of the new RR 'ctx->update_rr', + * with TTL 'ctx->update_rr_ttl', to its rdataset, by deleting + * the RRs if it is replaced by the new RR or has a conflicting TTL. + * The necessary changes are appended to ctx->del_diff and ctx->add_diff; + * we need to do all deletions before any additions so that we don't run + * into transient states with conflicting TTLs. + */ + +typedef struct { + dns_db_t *db; + dns_dbversion_t *ver; + dns_diff_t *diff; + dns_name_t *name; + dns_rdata_t *update_rr; + dns_ttl_t update_rr_ttl; + isc_boolean_t ignore_add; + dns_diff_t del_diff; + dns_diff_t add_diff; +} add_rr_prepare_ctx_t; + +static isc_result_t +add_rr_prepare_action(void *data, rr_t *rr) { + isc_result_t result = ISC_R_SUCCESS; + add_rr_prepare_ctx_t *ctx = data; + dns_difftuple_t *tuple = NULL; + isc_boolean_t equal; + + /* + * If the update RR is a "duplicate" of the update RR, + * the update should be silently ignored. + */ + equal = ISC_TF(dns_rdata_compare(&rr->rdata, ctx->update_rr) == 0); + if (equal && rr->ttl == ctx->update_rr_ttl) { + ctx->ignore_add = ISC_TRUE; + return (ISC_R_SUCCESS); + } + + /* + * If this RR is "equal" to the update RR, it should + * be deleted before the update RR is added. + */ + if (replaces_p(ctx->update_rr, &rr->rdata)) { + CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL, + ctx->name, rr->ttl, &rr->rdata, + &tuple)); + dns_diff_append(&ctx->del_diff, &tuple); + return (ISC_R_SUCCESS); + } + + /* + * If this RR differs in TTL from the update RR, + * its TTL must be adjusted. + */ + if (rr->ttl != ctx->update_rr_ttl) { + CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL, + ctx->name, rr->ttl, &rr->rdata, + &tuple)); + dns_diff_append(&ctx->del_diff, &tuple); + if (!equal) { + CHECK(dns_difftuple_create(ctx->add_diff.mctx, + DNS_DIFFOP_ADD, ctx->name, + ctx->update_rr_ttl, + &rr->rdata, &tuple)); + dns_diff_append(&ctx->add_diff, &tuple); + } + } + failure: + return (result); +} + +/**************************************************************************/ +/* + * Miscellaneous subroutines. + */ + +/*% + * Extract a single update RR from 'section' of dynamic update message + * 'msg', with consistency checking. + * + * Stores the owner name, rdata, and TTL of the update RR at 'name', + * 'rdata', and 'ttl', respectively. + */ +static void +get_current_rr(dns_message_t *msg, dns_section_t section, + dns_rdataclass_t zoneclass, dns_name_t **name, + dns_rdata_t *rdata, dns_rdatatype_t *covers, + dns_ttl_t *ttl, dns_rdataclass_t *update_class) +{ + dns_rdataset_t *rdataset; + isc_result_t result; + dns_message_currentname(msg, section, name); + rdataset = ISC_LIST_HEAD((*name)->list); + INSIST(rdataset != NULL); + INSIST(ISC_LIST_NEXT(rdataset, link) == NULL); + *covers = rdataset->covers; + *ttl = rdataset->ttl; + result = dns_rdataset_first(rdataset); + INSIST(result == ISC_R_SUCCESS); + dns_rdataset_current(rdataset, rdata); + INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE); + *update_class = rdata->rdclass; + rdata->rdclass = zoneclass; +} + +/*% + * Increment the SOA serial number of database 'db', version 'ver'. + * Replace the SOA record in the database, and log the + * change in 'diff'. + */ + + /* + * XXXRTH Failures in this routine will be worth logging, when + * we have a logging system. Failure to find the zonename + * or the SOA rdataset warrant at least an UNEXPECTED_ERROR(). + */ + +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; + + CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_DEL, &deltuple)); + CHECK(dns_difftuple_copy(deltuple, &addtuple)); + addtuple->op = DNS_DIFFOP_ADD; + + serial = dns_soa_getserial(&addtuple->rdata); + + /* 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; + + failure: + if (addtuple != NULL) + dns_difftuple_free(&addtuple); + if (deltuple != NULL) + dns_difftuple_free(&deltuple); + return (result); +} + +/*% + * Check that the new SOA record at 'update_rdata' does not + * illegally cause the SOA serial number to decrease or stay + * unchanged relative to the existing SOA in 'db'. + * + * Sets '*ok' to ISC_TRUE if the update is legal, ISC_FALSE if not. + * + * William King points out that RFC2136 is inconsistent about + * the case where the serial number stays unchanged: + * + * section 3.4.2.2 requires a server to ignore a SOA update request + * if the serial number on the update SOA is less_than_or_equal to + * the zone SOA serial. + * + * section 3.6 requires a server to ignore a SOA update request if + * the serial is less_than the zone SOA serial. + * + * Paul says 3.4.2.2 is correct. + * + */ +static isc_result_t +check_soa_increment(dns_db_t *db, dns_dbversion_t *ver, + dns_rdata_t *update_rdata, isc_boolean_t *ok) +{ + isc_uint32_t db_serial; + isc_uint32_t update_serial; + isc_result_t result; + + update_serial = dns_soa_getserial(update_rdata); + + result = dns_db_getsoaserial(db, ver, &db_serial); + if (result != ISC_R_SUCCESS) + return (result); + + if (DNS_SERIAL_GE(db_serial, update_serial)) { + *ok = ISC_FALSE; + } else { + *ok = ISC_TRUE; + } + + return (ISC_R_SUCCESS); + +} + +/**************************************************************************/ +/* + * Incremental updating of NSECs and RRSIGs. + */ + +#define MAXZONEKEYS 32 /*%< Maximum number of zone keys supported. */ + +/*% + * We abuse the dns_diff_t type to represent a set of domain names + * affected by the update. + */ +static isc_result_t +namelist_append_name(dns_diff_t *list, dns_name_t *name) { + isc_result_t result; + dns_difftuple_t *tuple = NULL; + static dns_rdata_t dummy_rdata = DNS_RDATA_INIT; + + CHECK(dns_difftuple_create(list->mctx, DNS_DIFFOP_EXISTS, name, 0, + &dummy_rdata, &tuple)); + dns_diff_append(list, &tuple); + failure: + return (result); +} + +static isc_result_t +namelist_append_subdomain(dns_db_t *db, dns_name_t *name, dns_diff_t *affected) +{ + isc_result_t result; + dns_fixedname_t fixedname; + dns_name_t *child; + dns_dbiterator_t *dbit = NULL; + + dns_fixedname_init(&fixedname); + child = dns_fixedname_name(&fixedname); + + CHECK(dns_db_createiterator(db, ISC_FALSE, &dbit)); + + for (result = dns_dbiterator_seek(dbit, name); + result == ISC_R_SUCCESS; + result = dns_dbiterator_next(dbit)) + { + dns_dbnode_t *node = NULL; + CHECK(dns_dbiterator_current(dbit, &node, child)); + dns_db_detachnode(db, &node); + if (! dns_name_issubdomain(child, name)) + break; + CHECK(namelist_append_name(affected, child)); + } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + failure: + if (dbit != NULL) + dns_dbiterator_destroy(&dbit); + return (result); +} + + + +/*% + * Helper function for non_nsec_rrset_exists(). + */ +static isc_result_t +is_non_nsec_action(void *data, dns_rdataset_t *rrset) { + UNUSED(data); + if (!(rrset->type == dns_rdatatype_nsec || + (rrset->type == dns_rdatatype_rrsig && + rrset->covers == dns_rdatatype_nsec))) + return (ISC_R_EXISTS); + return (ISC_R_SUCCESS); +} + +/*% + * Check whether there is an rrset other than a NSEC or RRSIG NSEC, + * i.e., anything that justifies the continued existence of a name + * after a secure update. + * + * If such an rrset exists, set '*exists' to ISC_TRUE. + * Otherwise, set it to ISC_FALSE. + */ +static isc_result_t +non_nsec_rrset_exists(dns_db_t *db, dns_dbversion_t *ver, + dns_name_t *name, isc_boolean_t *exists) +{ + isc_result_t result; + result = foreach_rrset(db, ver, name, is_non_nsec_action, NULL); + RETURN_EXISTENCE_FLAG; +} + +/*% + * A comparison function for sorting dns_diff_t:s by name. + */ +static int +name_order(const void *av, const void *bv) { + dns_difftuple_t const * const *ap = av; + dns_difftuple_t const * const *bp = bv; + dns_difftuple_t const *a = *ap; + dns_difftuple_t const *b = *bp; + return (dns_name_compare(&a->name, &b->name)); +} + +static isc_result_t +uniqify_name_list(dns_diff_t *list) { + isc_result_t result; + dns_difftuple_t *p, *q; + + CHECK(dns_diff_sort(list, name_order)); + + p = ISC_LIST_HEAD(list->tuples); + while (p != NULL) { + do { + q = ISC_LIST_NEXT(p, link); + if (q == NULL || ! dns_name_equal(&p->name, &q->name)) + break; + ISC_LIST_UNLINK(list->tuples, q, link); + dns_difftuple_free(&q); + } while (1); + p = ISC_LIST_NEXT(p, link); + } + failure: + return (result); +} + +static isc_result_t +is_active(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, + isc_boolean_t *flag, isc_boolean_t *cut, isc_boolean_t *unsecure) +{ + isc_result_t result; + dns_fixedname_t foundname; + dns_fixedname_init(&foundname); + result = dns_db_find(db, name, ver, dns_rdatatype_any, + DNS_DBFIND_GLUEOK | DNS_DBFIND_NOWILD, + (isc_stdtime_t) 0, NULL, + dns_fixedname_name(&foundname), + NULL, NULL); + if (result == ISC_R_SUCCESS || result == DNS_R_EMPTYNAME) { + *flag = ISC_TRUE; + *cut = ISC_FALSE; + if (unsecure != NULL) + *unsecure = ISC_FALSE; + return (ISC_R_SUCCESS); + } else if (result == DNS_R_ZONECUT) { + *flag = ISC_TRUE; + *cut = ISC_TRUE; + if (unsecure != NULL) { + /* + * We are at the zonecut. Check to see if there + * is a DS RRset. + */ + if (dns_db_find(db, name, ver, dns_rdatatype_ds, 0, + (isc_stdtime_t) 0, NULL, + dns_fixedname_name(&foundname), + NULL, NULL) == DNS_R_NXRRSET) + *unsecure = ISC_TRUE; + else + *unsecure = ISC_FALSE; + } + return (ISC_R_SUCCESS); + } else if (result == DNS_R_GLUE || result == DNS_R_DNAME || + result == DNS_R_DELEGATION || result == DNS_R_NXDOMAIN) { + *flag = ISC_FALSE; + *cut = ISC_FALSE; + if (unsecure != NULL) + *unsecure = ISC_FALSE; + return (ISC_R_SUCCESS); + } else { + /* + * Silence compiler. + */ + *flag = ISC_FALSE; + *cut = ISC_FALSE; + if (unsecure != NULL) + *unsecure = ISC_FALSE; + return (result); + } +} + +/*% + * Find the next/previous name that has a NSEC record. + * In other words, skip empty database nodes and names that + * have had their NSECs removed because they are obscured by + * a zone cut. + */ +static isc_result_t +next_active(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, + dns_dbversion_t *ver, dns_name_t *oldname, dns_name_t *newname, + isc_boolean_t forward) +{ + isc_result_t result; + dns_dbiterator_t *dbit = NULL; + isc_boolean_t has_nsec; + unsigned int wraps = 0; + + CHECK(dns_db_createiterator(db, ISC_FALSE, &dbit)); + + CHECK(dns_dbiterator_seek(dbit, oldname)); + do { + dns_dbnode_t *node = NULL; + + if (forward) + result = dns_dbiterator_next(dbit); + else + result = dns_dbiterator_prev(dbit); + if (result == ISC_R_NOMORE) { + /* + * Wrap around. + */ + if (forward) + CHECK(dns_dbiterator_first(dbit)); + else + CHECK(dns_dbiterator_last(dbit)); + wraps++; + if (wraps == 2) { + update_log(client, zone, ISC_LOG_ERROR, + "secure zone with no NSECs"); + result = DNS_R_BADZONE; + goto failure; + } + } + CHECK(dns_dbiterator_current(dbit, &node, newname)); + dns_db_detachnode(db, &node); + + /* + * The iterator may hold the tree lock, and + * rrset_exists() calls dns_db_findnode() which + * may try to reacquire it. To avoid deadlock + * we must pause the iterator first. + */ + CHECK(dns_dbiterator_pause(dbit)); + CHECK(rrset_exists(db, ver, newname, + dns_rdatatype_nsec, 0, &has_nsec)); + + } while (! has_nsec); + failure: + if (dbit != NULL) + dns_dbiterator_destroy(&dbit); + + return (result); +} + +/*% + * Add a NSEC record for "name", recording the change in "diff". + * The existing NSEC is removed. + */ +static isc_result_t +add_nsec(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, + dns_dbversion_t *ver, dns_name_t *name, dns_ttl_t nsecttl, + dns_diff_t *diff) +{ + isc_result_t result; + dns_dbnode_t *node = NULL; + unsigned char buffer[DNS_NSEC_BUFFERSIZE]; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_difftuple_t *tuple = NULL; + dns_fixedname_t fixedname; + dns_name_t *target; + + dns_fixedname_init(&fixedname); + target = dns_fixedname_name(&fixedname); + + /* + * Find the successor name, aka NSEC target. + */ + CHECK(next_active(client, zone, db, ver, name, target, ISC_TRUE)); + + /* + * Create the NSEC RDATA. + */ + CHECK(dns_db_findnode(db, name, ISC_FALSE, &node)); + dns_rdata_init(&rdata); + CHECK(dns_nsec_buildrdata(db, ver, node, target, buffer, &rdata)); + dns_db_detachnode(db, &node); + + /* + * Delete the old NSEC and record the change. + */ + CHECK(delete_if(true_p, db, ver, name, dns_rdatatype_nsec, 0, + NULL, diff)); + /* + * Add the new NSEC and record the change. + */ + CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, + nsecttl, &rdata, &tuple)); + CHECK(do_one_tuple(&tuple, db, ver, diff)); + INSIST(tuple == NULL); + + failure: + if (node != NULL) + dns_db_detachnode(db, &node); + return (result); +} + +/*% + * Add a placeholder NSEC record for "name", recording the change in "diff". + */ +static isc_result_t +add_placeholder_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, + dns_diff_t *diff) +{ + isc_result_t result; + dns_difftuple_t *tuple = NULL; + isc_region_t r; + unsigned char data[1] = { 0 }; /* The root domain, no bits. */ + dns_rdata_t rdata = DNS_RDATA_INIT; + + r.base = data; + r.length = sizeof(data); + dns_rdata_fromregion(&rdata, dns_db_class(db), dns_rdatatype_nsec, &r); + CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, 0, + &rdata, &tuple)); + CHECK(do_one_tuple(&tuple, db, ver, diff)); + failure: + return (result); +} + +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)); + CHECK(dns_dnssec_findzonekeys2(db, ver, node, dns_db_origin(db), + directory, mctx, maxkeys, keys, nkeys)); + failure: + if (node != NULL) + dns_db_detachnode(db, &node); + return (result); +} + +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; + + 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); + } + 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); +} + +/*% + * Add RRSIG records for an RRset, recording the change in "diff". + */ +static isc_result_t +add_sigs(ns_client_t *client, dns_zone_t *zone, 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_stdtime_t inception, isc_stdtime_t expire, + isc_boolean_t check_ksk) +{ + isc_result_t result; + dns_dbnode_t *node = NULL; + dns_rdataset_t rdataset; + dns_rdata_t sig_rdata = DNS_RDATA_INIT; + isc_buffer_t buffer; + unsigned char data[1024]; /* XXX */ + unsigned int i; + isc_boolean_t added_sig = ISC_FALSE; + isc_mem_t *mctx = client->mctx; + + dns_rdataset_init(&rdataset); + isc_buffer_init(&buffer, data, sizeof(data)); + + /* Get the rdataset to sign. */ + CHECK(dns_db_findnode(db, name, ISC_FALSE, &node)); + CHECK(dns_db_findrdataset(db, node, ver, type, 0, + (isc_stdtime_t) 0, &rdataset, NULL)); + dns_db_detachnode(db, &node); + + for (i = 0; i < nkeys; i++) { + + if (check_ksk && type != dns_rdatatype_dnskey && + (dst_key_flags(keys[i]) & DNS_KEYFLAG_KSK) != 0) + continue; + + if (!dst_key_isprivate(keys[i])) + continue; + + /* Calculate the signature, creating a RRSIG RDATA. */ + CHECK(dns_dnssec_sign(name, &rdataset, keys[i], + &inception, &expire, + mctx, &buffer, &sig_rdata)); + + /* Update the database and journal with the RRSIG. */ + /* XXX inefficient - will cause dataset merging */ + CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADD, name, + rdataset.ttl, &sig_rdata)); + dns_rdata_reset(&sig_rdata); + added_sig = ISC_TRUE; + } + if (!added_sig) { + update_log(client, zone, ISC_LOG_ERROR, + "found no private keys, " + "unable to generate any signatures"); + result = ISC_R_NOTFOUND; + } + + failure: + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + if (node != NULL) + dns_db_detachnode(db, &node); + return (result); +} + +static isc_result_t +add_exposed_sigs(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, + dns_dbversion_t *ver, dns_name_t *name, isc_boolean_t cut, + dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys, + isc_stdtime_t inception, isc_stdtime_t expire, + isc_boolean_t check_ksk) +{ + isc_result_t result; + dns_dbnode_t *node; + dns_rdatasetiter_t *iter; + + node = NULL; + result = dns_db_findnode(db, name, ISC_FALSE, &node); + if (result == ISC_R_NOTFOUND) + return (ISC_R_SUCCESS); + if (result != ISC_R_SUCCESS) + return (result); + + iter = NULL; + result = dns_db_allrdatasets(db, node, ver, + (isc_stdtime_t) 0, &iter); + if (result != ISC_R_SUCCESS) + goto cleanup_node; + + for (result = dns_rdatasetiter_first(iter); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(iter)) + { + dns_rdataset_t rdataset; + dns_rdatatype_t type; + isc_boolean_t flag; + + dns_rdataset_init(&rdataset); + dns_rdatasetiter_current(iter, &rdataset); + type = rdataset.type; + dns_rdataset_disassociate(&rdataset); + + /* + * We don't need to sign unsigned NSEC records at the cut + * as they are handled elsewhere. + */ + if ((type == dns_rdatatype_rrsig) || + (cut && type != dns_rdatatype_ds)) + continue; + result = rrset_exists(db, ver, name, dns_rdatatype_rrsig, + type, &flag); + if (result != ISC_R_SUCCESS) + goto cleanup_iterator; + if (flag) + continue;; + result = add_sigs(client, zone, db, ver, name, type, diff, + keys, nkeys, inception, expire, check_ksk); + if (result != ISC_R_SUCCESS) + goto cleanup_iterator; + } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + + cleanup_iterator: + dns_rdatasetiter_destroy(&iter); + + cleanup_node: + dns_db_detachnode(db, &node); + + return (result); +} + +/*% + * Update RRSIG and NSEC records affected by an update. The original + * update, including the SOA serial update but excluding the RRSIG & NSEC + * changes, is in "diff" and has already been applied to "newver" of "db". + * The database version prior to the update is "oldver". + * + * The necessary RRSIG and NSEC changes will be applied to "newver" + * and added (as a minimal diff) to "diff". + * + * The RRSIGs generated will be valid for 'sigvalidityinterval' seconds. + */ +static isc_result_t +update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, + dns_dbversion_t *oldver, dns_dbversion_t *newver, + dns_diff_t *diff, isc_uint32_t sigvalidityinterval) +{ + isc_result_t result; + dns_difftuple_t *t; + dns_diff_t diffnames; + dns_diff_t affected; + dns_diff_t sig_diff; + dns_diff_t nsec_diff; + dns_diff_t nsec_mindiff; + isc_boolean_t flag; + dst_key_t *zone_keys[MAXZONEKEYS]; + unsigned int nkeys = 0; + unsigned int i; + isc_stdtime_t now, inception, expire; + dns_ttl_t nsecttl; + dns_rdata_soa_t soa; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_t rdataset; + dns_dbnode_t *node = NULL; + isc_boolean_t check_ksk; + isc_boolean_t cut; + + dns_diff_init(client->mctx, &diffnames); + dns_diff_init(client->mctx, &affected); + + dns_diff_init(client->mctx, &sig_diff); + dns_diff_init(client->mctx, &nsec_diff); + dns_diff_init(client->mctx, &nsec_mindiff); + + result = find_zone_keys(zone, db, newver, client->mctx, + MAXZONEKEYS, zone_keys, &nkeys); + if (result != ISC_R_SUCCESS) { + update_log(client, zone, ISC_LOG_ERROR, + "could not get zone keys for secure dynamic update"); + goto failure; + } + + isc_stdtime_get(&now); + inception = now - 3600; /* Allow for some clock skew. */ + expire = now + sigvalidityinterval; + + /* + * Do we look at the KSK flag on the DNSKEY to determining which + * keys sign which RRsets? First check the zone option then + * check the keys flags to make sure at least one has a ksk set + * and one doesn't. + */ + check_ksk = ISC_TF((dns_zone_getoptions(zone) & + DNS_ZONEOPT_UPDATECHECKKSK) != 0); + if (check_ksk) + check_ksk = ksk_sanity(db, newver); + + /* + * Get the NSEC's TTL from the SOA MINIMUM field. + */ + CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node)); + dns_rdataset_init(&rdataset); + CHECK(dns_db_findrdataset(db, node, newver, dns_rdatatype_soa, 0, + (isc_stdtime_t) 0, &rdataset, NULL)); + CHECK(dns_rdataset_first(&rdataset)); + dns_rdataset_current(&rdataset, &rdata); + CHECK(dns_rdata_tostruct(&rdata, &soa, NULL)); + nsecttl = soa.minimum; + dns_rdataset_disassociate(&rdataset); + dns_db_detachnode(db, &node); + + /* + * Find all RRsets directly affected by the update, and + * update their RRSIGs. Also build a list of names affected + * by the update in "diffnames". + */ + CHECK(dns_diff_sort(diff, temp_order)); + + t = ISC_LIST_HEAD(diff->tuples); + while (t != NULL) { + dns_name_t *name = &t->name; + /* Now "name" is a new, unique name affected by the update. */ + + CHECK(namelist_append_name(&diffnames, name)); + + while (t != NULL && dns_name_equal(&t->name, name)) { + dns_rdatatype_t type; + type = t->rdata.type; + + /* + * Now "name" and "type" denote a new unique RRset + * affected by the update. + */ + + /* Don't sign RRSIGs. */ + if (type == dns_rdatatype_rrsig) + goto skip; + + /* + * Delete all old RRSIGs covering this type, since they + * are all invalid when the signed RRset has changed. + * We may not be able to recreate all of them - tough. + */ + CHECK(delete_if(true_p, db, newver, name, + dns_rdatatype_rrsig, type, + NULL, &sig_diff)); + + /* + * If this RRset is still visible after the update, + * add a new signature for it. + */ + CHECK(rrset_visible(db, newver, name, type, &flag)); + if (flag) { + CHECK(add_sigs(client, zone, db, newver, name, + type, &sig_diff, zone_keys, + nkeys, inception, expire, + check_ksk)); + } + skip: + /* Skip any other updates to the same RRset. */ + while (t != NULL && + dns_name_equal(&t->name, name) && + t->rdata.type == type) + { + t = ISC_LIST_NEXT(t, link); + } + } + } + + /* Remove orphaned NSECs and RRSIG NSECs. */ + for (t = ISC_LIST_HEAD(diffnames.tuples); + t != NULL; + t = ISC_LIST_NEXT(t, link)) + { + CHECK(non_nsec_rrset_exists(db, newver, &t->name, &flag)); + if (! flag) { + CHECK(delete_if(true_p, db, newver, &t->name, + dns_rdatatype_any, 0, + NULL, &sig_diff)); + } + } + + /* + * When a name is created or deleted, its predecessor needs to + * have its NSEC updated. + */ + for (t = ISC_LIST_HEAD(diffnames.tuples); + t != NULL; + t = ISC_LIST_NEXT(t, link)) + { + isc_boolean_t existed, exists; + dns_fixedname_t fixedname; + dns_name_t *prevname; + + dns_fixedname_init(&fixedname); + prevname = dns_fixedname_name(&fixedname); + + CHECK(name_exists(db, oldver, &t->name, &existed)); + CHECK(name_exists(db, newver, &t->name, &exists)); + if (exists == existed) + continue; + + /* + * Find the predecessor. + * When names become obscured or unobscured in this update + * transaction, we may find the wrong predecessor because + * the NSECs have not yet been updated to reflect the delegation + * change. This should not matter because in this case, + * the correct predecessor is either the delegation node or + * a newly unobscured node, and those nodes are on the + * "affected" list in any case. + */ + CHECK(next_active(client, zone, db, newver, + &t->name, prevname, ISC_FALSE)); + CHECK(namelist_append_name(&affected, prevname)); + } + + /* + * Find names potentially affected by delegation changes + * (obscured by adding an NS or DNAME, or unobscured by + * removing one). + */ + for (t = ISC_LIST_HEAD(diffnames.tuples); + t != NULL; + t = ISC_LIST_NEXT(t, link)) + { + isc_boolean_t ns_existed, dname_existed; + isc_boolean_t ns_exists, dname_exists; + + CHECK(rrset_exists(db, oldver, &t->name, dns_rdatatype_ns, 0, + &ns_existed)); + CHECK(rrset_exists(db, oldver, &t->name, dns_rdatatype_dname, 0, + &dname_existed)); + CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_ns, 0, + &ns_exists)); + CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_dname, 0, + &dname_exists)); + if ((ns_exists || dname_exists) == (ns_existed || dname_existed)) + continue; + /* + * There was a delegation change. Mark all subdomains + * of t->name as potentially needing a NSEC update. + */ + CHECK(namelist_append_subdomain(db, &t->name, &affected)); + } + + ISC_LIST_APPENDLIST(affected.tuples, diffnames.tuples, link); + INSIST(ISC_LIST_EMPTY(diffnames.tuples)); + + CHECK(uniqify_name_list(&affected)); + + /* + * Determine which names should have NSECs, and delete/create + * NSECs to make it so. We don't know the final NSEC targets yet, + * so we just create placeholder NSECs with arbitrary contents + * to indicate that their respective owner names should be part of + * the NSEC chain. + */ + for (t = ISC_LIST_HEAD(affected.tuples); + t != NULL; + t = ISC_LIST_NEXT(t, link)) + { + isc_boolean_t exists; + dns_name_t *name = &t->name; + + CHECK(name_exists(db, newver, name, &exists)); + if (! exists) + continue; + CHECK(is_active(db, newver, name, &flag, &cut, NULL)); + if (!flag) { + /* + * This name is obscured. Delete any + * existing NSEC record. + */ + CHECK(delete_if(true_p, db, newver, name, + dns_rdatatype_nsec, 0, + NULL, &nsec_diff)); + CHECK(delete_if(rrsig_p, db, newver, name, + dns_rdatatype_any, 0, NULL, diff)); + } else { + /* + * This name is not obscured. It should have a NSEC. + */ + CHECK(rrset_exists(db, newver, name, + dns_rdatatype_nsec, 0, &flag)); + if (! flag) + CHECK(add_placeholder_nsec(db, newver, &t->name, + diff)); + CHECK(add_exposed_sigs(client, zone, db, newver, name, + cut, diff, zone_keys, nkeys, + inception, expire, check_ksk)); + } + } + + /* + * Now we know which names are part of the NSEC chain. + * Make them all point at their correct targets. + */ + for (t = ISC_LIST_HEAD(affected.tuples); + t != NULL; + t = ISC_LIST_NEXT(t, link)) + { + CHECK(rrset_exists(db, newver, &t->name, + dns_rdatatype_nsec, 0, &flag)); + if (flag) { + /* + * There is a NSEC, but we don't know if it is correct. + * Delete it and create a correct one to be sure. + * If the update was unnecessary, the diff minimization + * will take care of eliminating it from the journal, + * IXFRs, etc. + * + * The RRSIG bit should always be set in the NSECs + * we generate, because they will all get RRSIG NSECs. + * (XXX what if the zone keys are missing?). + * Because the RRSIG NSECs have not necessarily been + * created yet, the correctness of the bit mask relies + * on the assumption that NSECs are only created if + * there is other data, and if there is other data, + * there are other RRSIGs. + */ + CHECK(add_nsec(client, zone, db, newver, &t->name, + nsecttl, &nsec_diff)); + } + } + + /* + * Minimize the set of NSEC updates so that we don't + * have to regenerate the RRSIG NSECs for NSECs that were + * replaced with identical ones. + */ + while ((t = ISC_LIST_HEAD(nsec_diff.tuples)) != NULL) { + ISC_LIST_UNLINK(nsec_diff.tuples, t, link); + dns_diff_appendminimal(&nsec_mindiff, &t); + } + + /* Update RRSIG NSECs. */ + for (t = ISC_LIST_HEAD(nsec_mindiff.tuples); + t != NULL; + t = ISC_LIST_NEXT(t, link)) + { + if (t->op == DNS_DIFFOP_DEL) { + CHECK(delete_if(true_p, db, newver, &t->name, + dns_rdatatype_rrsig, dns_rdatatype_nsec, + NULL, &sig_diff)); + } else if (t->op == DNS_DIFFOP_ADD) { + CHECK(add_sigs(client, zone, db, newver, &t->name, + dns_rdatatype_nsec, &sig_diff, + zone_keys, nkeys, inception, expire, + check_ksk)); + } else { + INSIST(0); + } + } + + /* Record our changes for the journal. */ + while ((t = ISC_LIST_HEAD(sig_diff.tuples)) != NULL) { + ISC_LIST_UNLINK(sig_diff.tuples, t, link); + dns_diff_appendminimal(diff, &t); + } + while ((t = ISC_LIST_HEAD(nsec_mindiff.tuples)) != NULL) { + ISC_LIST_UNLINK(nsec_mindiff.tuples, t, link); + dns_diff_appendminimal(diff, &t); + } + + INSIST(ISC_LIST_EMPTY(sig_diff.tuples)); + INSIST(ISC_LIST_EMPTY(nsec_diff.tuples)); + INSIST(ISC_LIST_EMPTY(nsec_mindiff.tuples)); + + failure: + dns_diff_clear(&sig_diff); + dns_diff_clear(&nsec_diff); + dns_diff_clear(&nsec_mindiff); + + dns_diff_clear(&affected); + dns_diff_clear(&diffnames); + + for (i = 0; i < nkeys; i++) + dst_key_free(&zone_keys[i]); + + return (result); +} + + +/**************************************************************************/ +/*% + * The actual update code in all its glory. We try to follow + * the RFC2136 pseudocode as closely as possible. + */ + +static isc_result_t +send_update_event(ns_client_t *client, dns_zone_t *zone) { + isc_result_t result = ISC_R_SUCCESS; + update_event_t *event = NULL; + isc_task_t *zonetask = NULL; + ns_client_t *evclient; + + event = (update_event_t *) + isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE, + update_action, NULL, sizeof(*event)); + if (event == NULL) + FAIL(ISC_R_NOMEMORY); + event->zone = zone; + event->result = ISC_R_SUCCESS; + + evclient = NULL; + ns_client_attach(client, &evclient); + INSIST(client->nupdates == 0); + client->nupdates++; + event->ev_arg = evclient; + + dns_zone_gettask(zone, &zonetask); + isc_task_send(zonetask, ISC_EVENT_PTR(&event)); + + failure: + if (event != NULL) + isc_event_free(ISC_EVENT_PTR(&event)); + return (result); +} + +static void +respond(ns_client_t *client, isc_result_t result) { + isc_result_t msg_result; + + msg_result = dns_message_reply(client->message, ISC_TRUE); + if (msg_result != ISC_R_SUCCESS) + goto msg_failure; + client->message->rcode = dns_result_torcode(result); + + ns_client_send(client); + return; + + msg_failure: + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE, + ISC_LOG_ERROR, + "could not create update response message: %s", + isc_result_totext(msg_result)); + ns_client_next(client, msg_result); +} + +void +ns_update_start(ns_client_t *client, isc_result_t sigresult) { + dns_message_t *request = client->message; + isc_result_t result; + dns_name_t *zonename; + dns_rdataset_t *zone_rdataset; + dns_zone_t *zone = NULL; + + /* + * Interpret the zone section. + */ + result = dns_message_firstname(request, DNS_SECTION_ZONE); + if (result != ISC_R_SUCCESS) + FAILC(DNS_R_FORMERR, "update zone section empty"); + + /* + * The zone section must contain exactly one "question", and + * it must be of type SOA. + */ + zonename = NULL; + dns_message_currentname(request, DNS_SECTION_ZONE, &zonename); + zone_rdataset = ISC_LIST_HEAD(zonename->list); + if (zone_rdataset->type != dns_rdatatype_soa) + FAILC(DNS_R_FORMERR, + "update zone section contains non-SOA"); + if (ISC_LIST_NEXT(zone_rdataset, link) != NULL) + FAILC(DNS_R_FORMERR, + "update zone section contains multiple RRs"); + + /* The zone section must have exactly one name. */ + result = dns_message_nextname(request, DNS_SECTION_ZONE); + if (result != ISC_R_NOMORE) + FAILC(DNS_R_FORMERR, + "update zone section contains multiple RRs"); + + result = dns_zt_find(client->view->zonetable, zonename, 0, NULL, + &zone); + if (result != ISC_R_SUCCESS) + FAILC(DNS_R_NOTAUTH, "not authoritative for update zone"); + + switch(dns_zone_gettype(zone)) { + case dns_zone_master: + /* + * We can now fail due to a bad signature as we now know + * that we are the master. + */ + if (sigresult != ISC_R_SUCCESS) + FAIL(sigresult); + CHECK(send_update_event(client, zone)); + break; + case dns_zone_slave: + CHECK(checkupdateacl(client, dns_zone_getforwardacl(zone), + "update forwarding", zonename, ISC_TRUE, + ISC_FALSE)); + CHECK(send_forward_event(client, zone)); + break; + default: + FAILC(DNS_R_NOTAUTH, "not authoritative for update zone"); + } + return; + + failure: + if (result == DNS_R_REFUSED) { + INSIST(dns_zone_gettype(zone) == dns_zone_slave); + inc_stats(zone, dns_nsstatscounter_updaterej); + } + /* + * We failed without having sent an update event to the zone. + * We are still in the client task context, so we can + * simply give an error response without switching tasks. + */ + respond(client, result); + if (zone != NULL) + dns_zone_detach(&zone); +} + +/*% + * DS records are not allowed to exist without corresponding NS records, + * draft-ietf-dnsext-delegation-signer-11.txt, 2.2 Protocol Change, + * "DS RRsets MUST NOT appear at non-delegation points or at a zone's apex". + */ + +static isc_result_t +remove_orphaned_ds(dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff) { + isc_result_t result; + isc_boolean_t ns_exists; + dns_difftuple_t *tupple; + dns_diff_t temp_diff; + + dns_diff_init(diff->mctx, &temp_diff); + + for (tupple = ISC_LIST_HEAD(diff->tuples); + tupple != NULL; + tupple = ISC_LIST_NEXT(tupple, link)) { + if (!((tupple->op == DNS_DIFFOP_DEL && + tupple->rdata.type == dns_rdatatype_ns) || + (tupple->op == DNS_DIFFOP_ADD && + tupple->rdata.type == dns_rdatatype_ds))) + continue; + CHECK(rrset_exists(db, newver, &tupple->name, + dns_rdatatype_ns, 0, &ns_exists)); + if (ns_exists && + !dns_name_equal(&tupple->name, dns_db_origin(db))) + continue; + CHECK(delete_if(true_p, db, newver, &tupple->name, + dns_rdatatype_ds, 0, NULL, &temp_diff)); + } + result = ISC_R_SUCCESS; + + failure: + for (tupple = ISC_LIST_HEAD(temp_diff.tuples); + tupple != NULL; + tupple = ISC_LIST_HEAD(temp_diff.tuples)) { + ISC_LIST_UNLINK(temp_diff.tuples, tupple, link); + dns_diff_appendminimal(diff, &tupple); + } + return (result); +} + +/* + * This implements the post load integrity checks for mx records. + */ +static isc_result_t +check_mx(ns_client_t *client, dns_zone_t *zone, + dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff) +{ + char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123.")]; + char ownerbuf[DNS_NAME_FORMATSIZE]; + char namebuf[DNS_NAME_FORMATSIZE]; + char altbuf[DNS_NAME_FORMATSIZE]; + dns_difftuple_t *t; + dns_fixedname_t fixed; + dns_name_t *foundname; + dns_rdata_mx_t mx; + dns_rdata_t rdata; + isc_boolean_t ok = ISC_TRUE; + isc_boolean_t isaddress; + isc_result_t result; + struct in6_addr addr6; + struct in_addr addr; + unsigned int options; + + dns_fixedname_init(&fixed); + foundname = dns_fixedname_name(&fixed); + dns_rdata_init(&rdata); + options = dns_zone_getoptions(zone); + + for (t = ISC_LIST_HEAD(diff->tuples); + t != NULL; + t = ISC_LIST_NEXT(t, link)) { + if (t->op != DNS_DIFFOP_ADD || + t->rdata.type != dns_rdatatype_mx) + continue; + + result = dns_rdata_tostruct(&t->rdata, &mx, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + /* + * Check if we will error out if we attempt to reload the + * zone. + */ + dns_name_format(&mx.mx, namebuf, sizeof(namebuf)); + dns_name_format(&t->name, ownerbuf, sizeof(ownerbuf)); + isaddress = ISC_FALSE; + if ((options & DNS_RDATA_CHECKMX) != 0 && + strlcpy(tmp, namebuf, sizeof(tmp)) < sizeof(tmp)) { + if (tmp[strlen(tmp) - 1] == '.') + tmp[strlen(tmp) - 1] = '\0'; + if (inet_aton(tmp, &addr) == 1 || + inet_pton(AF_INET6, tmp, &addr6) == 1) + isaddress = ISC_TRUE; + } + + if (isaddress && (options & DNS_RDATA_CHECKMXFAIL) != 0) { + update_log(client, zone, ISC_LOG_ERROR, + "%s/MX: '%s': %s", + ownerbuf, namebuf, + dns_result_totext(DNS_R_MXISADDRESS)); + ok = ISC_FALSE; + } else if (isaddress) { + update_log(client, zone, ISC_LOG_WARNING, + "%s/MX: warning: '%s': %s", + ownerbuf, namebuf, + dns_result_totext(DNS_R_MXISADDRESS)); + } + + /* + * Check zone integrity checks. + */ + if ((options & DNS_ZONEOPT_CHECKINTEGRITY) == 0) + continue; + result = dns_db_find(db, &mx.mx, newver, dns_rdatatype_a, + 0, 0, NULL, foundname, NULL, NULL); + if (result == ISC_R_SUCCESS) + continue; + + if (result == DNS_R_NXRRSET) { + result = dns_db_find(db, &mx.mx, newver, + dns_rdatatype_aaaa, + 0, 0, NULL, foundname, + NULL, NULL); + if (result == ISC_R_SUCCESS) + continue; + } + + if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN) { + update_log(client, zone, ISC_LOG_ERROR, + "%s/MX '%s' has no address records " + "(A or AAAA)", ownerbuf, namebuf); + ok = ISC_FALSE; + } else if (result == DNS_R_CNAME) { + update_log(client, zone, ISC_LOG_ERROR, + "%s/MX '%s' is a CNAME (illegal)", + ownerbuf, namebuf); + ok = ISC_FALSE; + } else if (result == DNS_R_DNAME) { + dns_name_format(foundname, altbuf, sizeof altbuf); + update_log(client, zone, ISC_LOG_ERROR, + "%s/MX '%s' is below a DNAME '%s' (illegal)", + ownerbuf, namebuf, altbuf); + ok = ISC_FALSE; + } + } + return (ok ? ISC_R_SUCCESS : DNS_R_REFUSED); +} + +static void +update_action(isc_task_t *task, isc_event_t *event) { + update_event_t *uev = (update_event_t *) event; + dns_zone_t *zone = uev->zone; + ns_client_t *client = (ns_client_t *)event->ev_arg; + + isc_result_t result; + dns_db_t *db = NULL; + dns_dbversion_t *oldver = NULL; + dns_dbversion_t *ver = NULL; + dns_diff_t diff; /* Pending updates. */ + dns_diff_t temp; /* Pending RR existence assertions. */ + isc_boolean_t soa_serial_changed = ISC_FALSE; + isc_mem_t *mctx = client->mctx; + dns_rdatatype_t covers; + dns_message_t *request = client->message; + dns_rdataclass_t zoneclass; + dns_name_t *zonename; + dns_ssutable_t *ssutable = NULL; + dns_fixedname_t tmpnamefixed; + dns_name_t *tmpname = NULL; + unsigned int options; + + INSIST(event->ev_type == DNS_EVENT_UPDATE); + + dns_diff_init(mctx, &diff); + dns_diff_init(mctx, &temp); + + CHECK(dns_zone_getdb(zone, &db)); + zonename = dns_db_origin(db); + zoneclass = dns_db_class(db); + dns_zone_getssutable(zone, &ssutable); + dns_db_currentversion(db, &oldver); + CHECK(dns_db_newversion(db, &ver)); + + /* + * Check prerequisites. + */ + + for (result = dns_message_firstname(request, DNS_SECTION_PREREQUISITE); + result == ISC_R_SUCCESS; + result = dns_message_nextname(request, DNS_SECTION_PREREQUISITE)) + { + dns_name_t *name = NULL; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_ttl_t ttl; + dns_rdataclass_t update_class; + isc_boolean_t flag; + + get_current_rr(request, DNS_SECTION_PREREQUISITE, zoneclass, + &name, &rdata, &covers, &ttl, &update_class); + + if (ttl != 0) + PREREQFAILC(DNS_R_FORMERR, + "prerequisite TTL is not zero"); + + if (! dns_name_issubdomain(name, zonename)) + PREREQFAILN(DNS_R_NOTZONE, name, + "prerequisite name is out of zone"); + + if (update_class == dns_rdataclass_any) { + if (rdata.length != 0) + PREREQFAILC(DNS_R_FORMERR, + "class ANY prerequisite " + "RDATA is not empty"); + if (rdata.type == dns_rdatatype_any) { + CHECK(name_exists(db, ver, name, &flag)); + if (! flag) { + PREREQFAILN(DNS_R_NXDOMAIN, name, + "'name in use' " + "prerequisite not " + "satisfied"); + } + } else { + CHECK(rrset_exists(db, ver, name, + rdata.type, covers, &flag)); + if (! flag) { + /* RRset does not exist. */ + PREREQFAILNT(DNS_R_NXRRSET, name, rdata.type, + "'rrset exists (value independent)' " + "prerequisite not satisfied"); + } + } + } else if (update_class == dns_rdataclass_none) { + if (rdata.length != 0) + PREREQFAILC(DNS_R_FORMERR, + "class NONE prerequisite " + "RDATA is not empty"); + if (rdata.type == dns_rdatatype_any) { + CHECK(name_exists(db, ver, name, &flag)); + if (flag) { + PREREQFAILN(DNS_R_YXDOMAIN, name, + "'name not in use' " + "prerequisite not " + "satisfied"); + } + } else { + CHECK(rrset_exists(db, ver, name, + rdata.type, covers, &flag)); + if (flag) { + /* RRset exists. */ + PREREQFAILNT(DNS_R_YXRRSET, name, + rdata.type, + "'rrset does not exist' " + "prerequisite not " + "satisfied"); + } + } + } else if (update_class == zoneclass) { + /* "temp += rr;" */ + result = temp_append(&temp, name, &rdata); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "temp entry creation failed: %s", + dns_result_totext(result)); + FAIL(ISC_R_UNEXPECTED); + } + } else { + PREREQFAILC(DNS_R_FORMERR, "malformed prerequisite"); + } + } + if (result != ISC_R_NOMORE) + FAIL(result); + + + /* + * Perform the final check of the "rrset exists (value dependent)" + * prerequisites. + */ + if (ISC_LIST_HEAD(temp.tuples) != NULL) { + dns_rdatatype_t type; + + /* + * Sort the prerequisite records by owner name, + * type, and rdata. + */ + result = dns_diff_sort(&temp, temp_order); + if (result != ISC_R_SUCCESS) + FAILC(result, "'RRset exists (value dependent)' " + "prerequisite not satisfied"); + + dns_fixedname_init(&tmpnamefixed); + tmpname = dns_fixedname_name(&tmpnamefixed); + result = temp_check(mctx, &temp, db, ver, tmpname, &type); + if (result != ISC_R_SUCCESS) + FAILNT(result, tmpname, type, + "'RRset exists (value dependent)' " + "prerequisite not satisfied"); + } + + update_log(client, zone, LOGLEVEL_DEBUG, + "prerequisites are OK"); + + /* + * Check Requestor's Permissions. It seems a bit silly to do this + * only after prerequisite testing, but that is what RFC2136 says. + */ + result = ISC_R_SUCCESS; + if (ssutable == NULL) + CHECK(checkupdateacl(client, dns_zone_getupdateacl(zone), + "update", zonename, ISC_FALSE, ISC_FALSE)); + else if (client->signer == NULL) + CHECK(checkupdateacl(client, NULL, "update", zonename, + ISC_FALSE, ISC_TRUE)); + + if (dns_zone_getupdatedisabled(zone)) + FAILC(DNS_R_REFUSED, "dynamic update temporarily disabled " + "because the zone is frozen. Use " + "'rndc thaw' to re-enable updates."); + + /* + * Perform the Update Section Prescan. + */ + + for (result = dns_message_firstname(request, DNS_SECTION_UPDATE); + result == ISC_R_SUCCESS; + result = dns_message_nextname(request, DNS_SECTION_UPDATE)) + { + dns_name_t *name = NULL; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_ttl_t ttl; + dns_rdataclass_t update_class; + get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, + &name, &rdata, &covers, &ttl, &update_class); + + if (! dns_name_issubdomain(name, zonename)) + FAILC(DNS_R_NOTZONE, + "update RR is outside zone"); + if (update_class == zoneclass) { + /* + * Check for meta-RRs. The RFC2136 pseudocode says + * check for ANY|AXFR|MAILA|MAILB, but the text adds + * "or any other QUERY metatype" + */ + if (dns_rdatatype_ismeta(rdata.type)) { + FAILC(DNS_R_FORMERR, + "meta-RR in update"); + } + result = dns_zone_checknames(zone, name, &rdata); + if (result != ISC_R_SUCCESS) + FAIL(DNS_R_REFUSED); + } else if (update_class == dns_rdataclass_any) { + if (ttl != 0 || rdata.length != 0 || + (dns_rdatatype_ismeta(rdata.type) && + rdata.type != dns_rdatatype_any)) + FAILC(DNS_R_FORMERR, + "meta-RR in update"); + } else if (update_class == dns_rdataclass_none) { + if (ttl != 0 || + dns_rdatatype_ismeta(rdata.type)) + FAILC(DNS_R_FORMERR, + "meta-RR in update"); + } else { + update_log(client, zone, ISC_LOG_WARNING, + "update RR has incorrect class %d", + update_class); + FAIL(DNS_R_FORMERR); + } + /* + * draft-ietf-dnsind-simple-secure-update-01 says + * "Unlike traditional dynamic update, the client + * is forbidden from updating NSEC records." + */ + if (dns_db_issecure(db)) { + if (rdata.type == dns_rdatatype_nsec) { + FAILC(DNS_R_REFUSED, + "explicit NSEC updates are not allowed " + "in secure zones"); + } + else if (rdata.type == dns_rdatatype_rrsig) { + FAILC(DNS_R_REFUSED, + "explicit RRSIG updates are currently not " + "supported in secure zones"); + } + } + + if (ssutable != NULL && client->signer != NULL) { + if (rdata.type != dns_rdatatype_any) { + if (!dns_ssutable_checkrules(ssutable, + client->signer, + name, rdata.type)) + FAILC(DNS_R_REFUSED, + "rejected by secure update"); + } + else { + if (!ssu_checkall(db, ver, name, ssutable, + client->signer)) + FAILC(DNS_R_REFUSED, + "rejected by secure update"); + } + } + } + if (result != ISC_R_NOMORE) + FAIL(result); + + update_log(client, zone, LOGLEVEL_DEBUG, + "update section prescan OK"); + + /* + * Process the Update Section. + */ + + options = dns_zone_getoptions(zone); + for (result = dns_message_firstname(request, DNS_SECTION_UPDATE); + result == ISC_R_SUCCESS; + result = dns_message_nextname(request, DNS_SECTION_UPDATE)) + { + dns_name_t *name = NULL; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_ttl_t ttl; + dns_rdataclass_t update_class; + isc_boolean_t flag; + + get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, + &name, &rdata, &covers, &ttl, &update_class); + + if (update_class == zoneclass) { + + /* + * RFC1123 doesn't allow MF and MD in master zones. */ + if (rdata.type == dns_rdatatype_md || + rdata.type == dns_rdatatype_mf) { + char typebuf[DNS_RDATATYPE_FORMATSIZE]; + + dns_rdatatype_format(rdata.type, typebuf, + sizeof(typebuf)); + update_log(client, zone, LOGLEVEL_PROTOCOL, + "attempt to add %s ignored", + typebuf); + continue; + } + if (rdata.type == dns_rdatatype_ns && + dns_name_iswildcard(name)) { + update_log(client, zone, + LOGLEVEL_PROTOCOL, + "attempt to add wildcard NS record" + "ignored"); + continue; + } + if (rdata.type == dns_rdatatype_cname) { + CHECK(cname_incompatible_rrset_exists(db, ver, + name, + &flag)); + if (flag) { + update_log(client, zone, + LOGLEVEL_PROTOCOL, + "attempt to add CNAME " + "alongside non-CNAME " + "ignored"); + continue; + } + } else { + CHECK(rrset_exists(db, ver, name, + dns_rdatatype_cname, 0, + &flag)); + if (flag && + ! dns_rdatatype_isdnssec(rdata.type)) + { + update_log(client, zone, + LOGLEVEL_PROTOCOL, + "attempt to add non-CNAME " + "alongside CNAME ignored"); + continue; + } + } + if (rdata.type == dns_rdatatype_soa) { + isc_boolean_t ok; + CHECK(rrset_exists(db, ver, name, + dns_rdatatype_soa, 0, + &flag)); + if (! flag) { + update_log(client, zone, + LOGLEVEL_PROTOCOL, + "attempt to create 2nd " + "SOA ignored"); + continue; + } + CHECK(check_soa_increment(db, ver, &rdata, + &ok)); + if (! ok) { + update_log(client, zone, + LOGLEVEL_PROTOCOL, + "SOA update failed to " + "increment serial, " + "ignoring it"); + continue; + } + soa_serial_changed = ISC_TRUE; + } + if ((options & DNS_ZONEOPT_CHECKWILDCARD) != 0 && + dns_name_internalwildcard(name)) { + char namestr[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namestr, + sizeof(namestr)); + update_log(client, zone, LOGLEVEL_PROTOCOL, + "warning: ownername '%s' contains " + "a non-terminal wildcard", namestr); + } + + if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) { + char namestr[DNS_NAME_FORMATSIZE]; + char typestr[DNS_RDATATYPE_FORMATSIZE]; + dns_name_format(name, namestr, + sizeof(namestr)); + dns_rdatatype_format(rdata.type, typestr, + sizeof(typestr)); + update_log(client, zone, LOGLEVEL_PROTOCOL, + "adding an RR at '%s' %s", + namestr, typestr); + } + + /* Prepare the affected RRset for the addition. */ + { + add_rr_prepare_ctx_t ctx; + ctx.db = db; + ctx.ver = ver; + ctx.diff = &diff; + ctx.name = name; + ctx.update_rr = &rdata; + ctx.update_rr_ttl = ttl; + ctx.ignore_add = ISC_FALSE; + dns_diff_init(mctx, &ctx.del_diff); + dns_diff_init(mctx, &ctx.add_diff); + CHECK(foreach_rr(db, ver, name, rdata.type, + covers, add_rr_prepare_action, + &ctx)); + + if (ctx.ignore_add) { + dns_diff_clear(&ctx.del_diff); + dns_diff_clear(&ctx.add_diff); + } else { + CHECK(do_diff(&ctx.del_diff, db, ver, &diff)); + CHECK(do_diff(&ctx.add_diff, db, ver, &diff)); + CHECK(update_one_rr(db, ver, &diff, + DNS_DIFFOP_ADD, + name, ttl, &rdata)); + } + } + } else if (update_class == dns_rdataclass_any) { + if (rdata.type == dns_rdatatype_any) { + if (isc_log_wouldlog(ns_g_lctx, + LOGLEVEL_PROTOCOL)) + { + char namestr[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namestr, + sizeof(namestr)); + update_log(client, zone, + LOGLEVEL_PROTOCOL, + "delete all rrsets from " + "name '%s'", namestr); + } + if (dns_name_equal(name, zonename)) { + CHECK(delete_if(type_not_soa_nor_ns_p, + db, ver, name, + dns_rdatatype_any, 0, + &rdata, &diff)); + } else { + CHECK(delete_if(type_not_dnssec, + db, ver, name, + dns_rdatatype_any, 0, + &rdata, &diff)); + } + } else if (dns_name_equal(name, zonename) && + (rdata.type == dns_rdatatype_soa || + rdata.type == dns_rdatatype_ns)) { + update_log(client, zone, LOGLEVEL_PROTOCOL, + "attempt to delete all SOA " + "or NS records ignored"); + continue; + } else { + if (isc_log_wouldlog(ns_g_lctx, + LOGLEVEL_PROTOCOL)) + { + char namestr[DNS_NAME_FORMATSIZE]; + char typestr[DNS_RDATATYPE_FORMATSIZE]; + dns_name_format(name, namestr, + sizeof(namestr)); + dns_rdatatype_format(rdata.type, + typestr, + sizeof(typestr)); + update_log(client, zone, + LOGLEVEL_PROTOCOL, + "deleting rrset at '%s' %s", + namestr, typestr); + } + CHECK(delete_if(true_p, db, ver, name, + rdata.type, covers, &rdata, + &diff)); + } + } else if (update_class == dns_rdataclass_none) { + /* + * The (name == zonename) condition appears in + * RFC2136 3.4.2.4 but is missing from the pseudocode. + */ + if (dns_name_equal(name, zonename)) { + if (rdata.type == dns_rdatatype_soa) { + update_log(client, zone, + LOGLEVEL_PROTOCOL, + "attempt to delete SOA " + "ignored"); + continue; + } + if (rdata.type == dns_rdatatype_ns) { + int count; + CHECK(rr_count(db, ver, name, + dns_rdatatype_ns, + 0, &count)); + if (count == 1) { + update_log(client, zone, + LOGLEVEL_PROTOCOL, + "attempt to " + "delete last " + "NS ignored"); + continue; + } + } + } + update_log(client, zone, + LOGLEVEL_PROTOCOL, + "deleting an RR"); + CHECK(delete_if(rr_equal_p, db, ver, name, + rdata.type, covers, &rdata, &diff)); + } + } + if (result != ISC_R_NOMORE) + FAIL(result); + + /* + * If any changes were made, increment the SOA serial number, + * update RRSIGs and NSECs (if zone is secure), and write the update + * to the journal. + */ + if (! ISC_LIST_EMPTY(diff.tuples)) { + char *journalfile; + dns_journal_t *journal; + + /* + * Increment the SOA serial, but only if it was not + * changed as a result of an update operation. + */ + if (! soa_serial_changed) { + CHECK(increment_soa_serial(db, ver, &diff, mctx)); + } + + CHECK(check_mx(client, zone, db, ver, &diff)); + + CHECK(remove_orphaned_ds(db, ver, &diff)); + + if (dns_db_issecure(db)) { + result = update_signatures(client, zone, db, oldver, + ver, &diff, + dns_zone_getsigvalidityinterval(zone)); + if (result != ISC_R_SUCCESS) { + update_log(client, zone, + ISC_LOG_ERROR, + "RRSIG/NSEC update failed: %s", + isc_result_totext(result)); + goto failure; + } + } + + journalfile = dns_zone_getjournal(zone); + if (journalfile != NULL) { + update_log(client, zone, LOGLEVEL_DEBUG, + "writing journal %s", journalfile); + + journal = NULL; + result = dns_journal_open(mctx, journalfile, + ISC_TRUE, &journal); + if (result != ISC_R_SUCCESS) + FAILS(result, "journal open failed"); + + result = dns_journal_write_transaction(journal, &diff); + if (result != ISC_R_SUCCESS) { + dns_journal_destroy(&journal); + FAILS(result, "journal write failed"); + } + + dns_journal_destroy(&journal); + } + + /* + * XXXRTH Just a note that this committing code will have + * to change to handle databases that need two-phase + * commit, but this isn't a priority. + */ + update_log(client, zone, LOGLEVEL_DEBUG, + "committing update transaction"); + dns_db_closeversion(db, &ver, ISC_TRUE); + + /* + * Mark the zone as dirty so that it will be written to disk. + */ + dns_zone_markdirty(zone); + + /* + * Notify slaves of the change we just made. + */ + dns_zone_notify(zone); + } else { + update_log(client, zone, LOGLEVEL_DEBUG, "redundant request"); + dns_db_closeversion(db, &ver, ISC_TRUE); + } + result = ISC_R_SUCCESS; + goto common; + + failure: + /* + * The reason for failure should have been logged at this point. + */ + if (ver != NULL) { + update_log(client, zone, LOGLEVEL_DEBUG, + "rolling back"); + dns_db_closeversion(db, &ver, ISC_FALSE); + } + + common: + dns_diff_clear(&temp); + dns_diff_clear(&diff); + + if (oldver != NULL) + dns_db_closeversion(db, &oldver, ISC_FALSE); + + if (db != NULL) + dns_db_detach(&db); + + if (ssutable != NULL) + dns_ssutable_detach(&ssutable); + + isc_task_detach(&task); + uev->result = result; + if (zone != NULL) + INSIST(uev->zone == zone); /* we use this later */ + uev->ev_type = DNS_EVENT_UPDATEDONE; + uev->ev_action = updatedone_action; + isc_task_send(client->task, &event); + INSIST(event == NULL); +} + +static void +updatedone_action(isc_task_t *task, isc_event_t *event) { + update_event_t *uev = (update_event_t *) event; + ns_client_t *client = (ns_client_t *) event->ev_arg; + + UNUSED(task); + + INSIST(event->ev_type == DNS_EVENT_UPDATEDONE); + INSIST(task == client->task); + + INSIST(client->nupdates > 0); + switch (uev->result) { + case ISC_R_SUCCESS: + inc_stats(uev->zone, dns_nsstatscounter_updatedone); + break; + case DNS_R_REFUSED: + inc_stats(uev->zone, dns_nsstatscounter_updaterej); + break; + default: + inc_stats(uev->zone, dns_nsstatscounter_updatefail); + break; + } + if (uev->zone != NULL) + dns_zone_detach(&uev->zone); + client->nupdates--; + respond(client, uev->result); + isc_event_free(&event); + ns_client_detach(&client); +} + +/*% + * Update forwarding support. + */ + +static void +forward_fail(isc_task_t *task, isc_event_t *event) { + ns_client_t *client = (ns_client_t *)event->ev_arg; + + UNUSED(task); + + INSIST(client->nupdates > 0); + client->nupdates--; + respond(client, DNS_R_SERVFAIL); + isc_event_free(&event); + ns_client_detach(&client); +} + + +static void +forward_callback(void *arg, isc_result_t result, dns_message_t *answer) { + update_event_t *uev = arg; + ns_client_t *client = uev->ev_arg; + dns_zone_t *zone = uev->zone; + + if (result != ISC_R_SUCCESS) { + INSIST(answer == NULL); + uev->ev_type = DNS_EVENT_UPDATEDONE; + uev->ev_action = forward_fail; + inc_stats(zone, dns_nsstatscounter_updatefwdfail); + } else { + uev->ev_type = DNS_EVENT_UPDATEDONE; + uev->ev_action = forward_done; + uev->answer = answer; + inc_stats(zone, dns_nsstatscounter_updaterespfwd); + } + isc_task_send(client->task, ISC_EVENT_PTR(&uev)); + dns_zone_detach(&zone); +} + +static void +forward_done(isc_task_t *task, isc_event_t *event) { + update_event_t *uev = (update_event_t *) event; + ns_client_t *client = (ns_client_t *)event->ev_arg; + + UNUSED(task); + + INSIST(client->nupdates > 0); + client->nupdates--; + ns_client_sendraw(client, uev->answer); + dns_message_destroy(&uev->answer); + isc_event_free(&event); + ns_client_detach(&client); +} + +static void +forward_action(isc_task_t *task, isc_event_t *event) { + update_event_t *uev = (update_event_t *) event; + dns_zone_t *zone = uev->zone; + ns_client_t *client = (ns_client_t *)event->ev_arg; + isc_result_t result; + + result = dns_zone_forwardupdate(zone, client->message, + forward_callback, event); + if (result != ISC_R_SUCCESS) { + uev->ev_type = DNS_EVENT_UPDATEDONE; + uev->ev_action = forward_fail; + isc_task_send(client->task, &event); + inc_stats(zone, dns_nsstatscounter_updatefwdfail); + dns_zone_detach(&zone); + } else + inc_stats(zone, dns_nsstatscounter_updatereqfwd); + isc_task_detach(&task); +} + +static isc_result_t +send_forward_event(ns_client_t *client, dns_zone_t *zone) { + isc_result_t result = ISC_R_SUCCESS; + update_event_t *event = NULL; + isc_task_t *zonetask = NULL; + ns_client_t *evclient; + + event = (update_event_t *) + isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE, + forward_action, NULL, sizeof(*event)); + if (event == NULL) + FAIL(ISC_R_NOMEMORY); + event->zone = zone; + event->result = ISC_R_SUCCESS; + + evclient = NULL; + ns_client_attach(client, &evclient); + INSIST(client->nupdates == 0); + client->nupdates++; + event->ev_arg = evclient; + + dns_zone_gettask(zone, &zonetask); + isc_task_send(zonetask, ISC_EVENT_PTR(&event)); + + failure: + if (event != NULL) + isc_event_free(ISC_EVENT_PTR(&event)); + return (result); +} diff --git a/contrib/bind-9.5.2/bin/named/xfrout.c b/contrib/bind-9.5.2/bin/named/xfrout.c new file mode 100644 index 0000000000..fc76a5b1a8 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/xfrout.c @@ -0,0 +1,1843 @@ +/* + * Copyright (C) 2004-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 + * 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: xfrout.c,v 1.126.128.8 2009/01/29 22:41:44 jinmei Exp $ */ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#ifdef DLZ +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/*! \file + * \brief + * Outgoing AXFR and IXFR. + */ + +/* + * TODO: + * - IXFR over UDP + */ + +#define XFROUT_COMMON_LOGARGS \ + ns_g_lctx, DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT + +#define XFROUT_PROTOCOL_LOGARGS \ + XFROUT_COMMON_LOGARGS, ISC_LOG_INFO + +#define XFROUT_DEBUG_LOGARGS(n) \ + XFROUT_COMMON_LOGARGS, ISC_LOG_DEBUG(n) + +#define XFROUT_RR_LOGARGS \ + XFROUT_COMMON_LOGARGS, XFROUT_RR_LOGLEVEL + +#define XFROUT_RR_LOGLEVEL ISC_LOG_DEBUG(8) + +/*% + * Fail unconditionally and log as a client error. + * The test against ISC_R_SUCCESS is there to keep the Solaris compiler + * from complaining about "end-of-loop code not reached". + */ +#define FAILC(code, msg) \ + do { \ + result = (code); \ + ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, \ + NS_LOGMODULE_XFER_OUT, ISC_LOG_INFO, \ + "bad zone transfer request: %s (%s)", \ + msg, isc_result_totext(code)); \ + if (result != ISC_R_SUCCESS) goto failure; \ + } while (0) + +#define FAILQ(code, msg, question, rdclass) \ + do { \ + char _buf1[DNS_NAME_FORMATSIZE]; \ + char _buf2[DNS_RDATACLASS_FORMATSIZE]; \ + result = (code); \ + dns_name_format(question, _buf1, sizeof(_buf1)); \ + dns_rdataclass_format(rdclass, _buf2, sizeof(_buf2)); \ + ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, \ + NS_LOGMODULE_XFER_OUT, ISC_LOG_INFO, \ + "bad zone transfer request: '%s/%s': %s (%s)", \ + _buf1, _buf2, msg, isc_result_totext(code)); \ + if (result != ISC_R_SUCCESS) goto failure; \ + } while (0) + +#define CHECK(op) \ + do { result = (op); \ + if (result != ISC_R_SUCCESS) goto failure; \ + } while (0) + +/**************************************************************************/ +/*% + * A db_rr_iterator_t is an iterator that iterates over an entire database, + * returning one RR at a time, in some arbitrary order. + */ + +typedef struct db_rr_iterator db_rr_iterator_t; + +/*% db_rr_iterator structure */ +struct db_rr_iterator { + 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; +}; + +static isc_result_t +db_rr_iterator_init(db_rr_iterator_t *it, dns_db_t *db, dns_dbversion_t *ver, + isc_stdtime_t now); + +static isc_result_t +db_rr_iterator_first(db_rr_iterator_t *it); + +static isc_result_t +db_rr_iterator_next(db_rr_iterator_t *it); + +static void +db_rr_iterator_current(db_rr_iterator_t *it, dns_name_t **name, + isc_uint32_t *ttl, dns_rdata_t **rdata); + +static void +db_rr_iterator_destroy(db_rr_iterator_t *it); + +static inline void +inc_stats(dns_zone_t *zone, isc_statscounter_t counter) { + isc_stats_increment(ns_g_server->nsstats, counter); + if (zone != NULL) { + isc_stats_t *zonestats = dns_zone_getrequeststats(zone); + if (zonestats != NULL) + isc_stats_increment(zonestats, counter); + } +} + +static isc_result_t +db_rr_iterator_init(db_rr_iterator_t *it, dns_db_t *db, dns_dbversion_t *ver, + isc_stdtime_t now) +{ + isc_result_t result; + it->db = db; + it->dbit = NULL; + it->ver = ver; + it->now = now; + it->node = NULL; + result = dns_db_createiterator(it->db, ISC_FALSE, &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); +} + +static isc_result_t +db_rr_iterator_first(db_rr_iterator_t *it) { + 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); +} + + +static isc_result_t +db_rr_iterator_next(db_rr_iterator_t *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) { + 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); + if (it->result != ISC_R_SUCCESS) + return (it->result); + } + return (it->result); +} + +static void +db_rr_iterator_pause(db_rr_iterator_t *it) { + RUNTIME_CHECK(dns_dbiterator_pause(it->dbit) == ISC_R_SUCCESS); +} + +static void +db_rr_iterator_destroy(db_rr_iterator_t *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); +} + +static void +db_rr_iterator_current(db_rr_iterator_t *it, dns_name_t **name, + isc_uint32_t *ttl, dns_rdata_t **rdata) +{ + REQUIRE(name != NULL && *name == NULL); + 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); + *rdata = &it->rdata; +} + +/**************************************************************************/ + +/*% Log an RR (for debugging) */ + +static void +log_rr(dns_name_t *name, dns_rdata_t *rdata, isc_uint32_t ttl) { + isc_result_t result; + isc_buffer_t buf; + char mem[2000]; + dns_rdatalist_t rdl; + dns_rdataset_t rds; + dns_rdata_t rd = DNS_RDATA_INIT; + + rdl.type = rdata->type; + rdl.rdclass = rdata->rdclass; + rdl.ttl = ttl; + if (rdata->type == dns_rdatatype_sig || + rdata->type == dns_rdatatype_rrsig) + rdl.covers = dns_rdata_covers(rdata); + else + rdl.covers = dns_rdatatype_none; + ISC_LIST_INIT(rdl.rdata); + ISC_LINK_INIT(&rdl, link); + dns_rdataset_init(&rds); + dns_rdata_init(&rd); + dns_rdata_clone(rdata, &rd); + ISC_LIST_APPEND(rdl.rdata, &rd, link); + RUNTIME_CHECK(dns_rdatalist_tordataset(&rdl, &rds) == ISC_R_SUCCESS); + + isc_buffer_init(&buf, mem, sizeof(mem)); + result = dns_rdataset_totext(&rds, name, + ISC_FALSE, ISC_FALSE, &buf); + + /* + * We could use xfrout_log(), but that would produce + * very long lines with a repetitive prefix. + */ + if (result == ISC_R_SUCCESS) { + /* + * Get rid of final newline. + */ + INSIST(buf.used >= 1 && + ((char *) buf.base)[buf.used - 1] == '\n'); + buf.used--; + + isc_log_write(XFROUT_RR_LOGARGS, "%.*s", + (int)isc_buffer_usedlength(&buf), + (char *)isc_buffer_base(&buf)); + } else { + isc_log_write(XFROUT_RR_LOGARGS, ""); + } +} + +/**************************************************************************/ +/* + * An 'rrstream_t' is a polymorphic iterator that returns + * a stream of resource records. There are multiple implementations, + * e.g. for generating AXFR and IXFR records streams. + */ + +typedef struct rrstream_methods rrstream_methods_t; + +typedef struct rrstream { + isc_mem_t *mctx; + rrstream_methods_t *methods; +} rrstream_t; + +struct rrstream_methods { + isc_result_t (*first)(rrstream_t *); + isc_result_t (*next)(rrstream_t *); + void (*current)(rrstream_t *, + dns_name_t **, + isc_uint32_t *, + dns_rdata_t **); + void (*pause)(rrstream_t *); + void (*destroy)(rrstream_t **); +}; + +static void +rrstream_noop_pause(rrstream_t *rs) { + UNUSED(rs); +} + +/**************************************************************************/ +/* + * An 'ixfr_rrstream_t' is an 'rrstream_t' that returns + * an IXFR-like RR stream from a journal file. + * + * The SOA at the beginning of each sequence of additions + * or deletions are included in the stream, but the extra + * SOAs at the beginning and end of the entire transfer are + * not included. + */ + +typedef struct ixfr_rrstream { + rrstream_t common; + dns_journal_t *journal; +} ixfr_rrstream_t; + +/* Forward declarations. */ +static void +ixfr_rrstream_destroy(rrstream_t **sp); + +static rrstream_methods_t ixfr_rrstream_methods; + +/* + * Returns: anything dns_journal_open() or dns_journal_iter_init() + * may return. + */ + +static isc_result_t +ixfr_rrstream_create(isc_mem_t *mctx, + const char *journal_filename, + isc_uint32_t begin_serial, + isc_uint32_t end_serial, + rrstream_t **sp) +{ + ixfr_rrstream_t *s; + isc_result_t result; + + INSIST(sp != NULL && *sp == NULL); + + s = isc_mem_get(mctx, sizeof(*s)); + if (s == NULL) + return (ISC_R_NOMEMORY); + s->common.mctx = mctx; + s->common.methods = &ixfr_rrstream_methods; + s->journal = NULL; + + CHECK(dns_journal_open(mctx, journal_filename, + ISC_FALSE, &s->journal)); + CHECK(dns_journal_iter_init(s->journal, begin_serial, end_serial)); + + *sp = (rrstream_t *) s; + return (ISC_R_SUCCESS); + + failure: + ixfr_rrstream_destroy((rrstream_t **) (void *)&s); + return (result); +} + +static isc_result_t +ixfr_rrstream_first(rrstream_t *rs) { + ixfr_rrstream_t *s = (ixfr_rrstream_t *) rs; + return (dns_journal_first_rr(s->journal)); +} + +static isc_result_t +ixfr_rrstream_next(rrstream_t *rs) { + ixfr_rrstream_t *s = (ixfr_rrstream_t *) rs; + return (dns_journal_next_rr(s->journal)); +} + +static void +ixfr_rrstream_current(rrstream_t *rs, + dns_name_t **name, isc_uint32_t *ttl, + dns_rdata_t **rdata) +{ + ixfr_rrstream_t *s = (ixfr_rrstream_t *) rs; + dns_journal_current_rr(s->journal, name, ttl, rdata); +} + +static void +ixfr_rrstream_destroy(rrstream_t **rsp) { + ixfr_rrstream_t *s = (ixfr_rrstream_t *) *rsp; + if (s->journal != 0) + dns_journal_destroy(&s->journal); + isc_mem_put(s->common.mctx, s, sizeof(*s)); +} + +static rrstream_methods_t ixfr_rrstream_methods = { + ixfr_rrstream_first, + ixfr_rrstream_next, + ixfr_rrstream_current, + rrstream_noop_pause, + ixfr_rrstream_destroy +}; + +/**************************************************************************/ +/* + * An 'axfr_rrstream_t' is an 'rrstream_t' that returns + * an AXFR-like RR stream from a database. + * + * The SOAs at the beginning and end of the transfer are + * not included in the stream. + */ + +typedef struct axfr_rrstream { + rrstream_t common; + db_rr_iterator_t it; + isc_boolean_t it_valid; +} axfr_rrstream_t; + +/* + * Forward declarations. + */ +static void +axfr_rrstream_destroy(rrstream_t **rsp); + +static rrstream_methods_t axfr_rrstream_methods; + +static isc_result_t +axfr_rrstream_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *ver, + rrstream_t **sp) +{ + axfr_rrstream_t *s; + isc_result_t result; + + INSIST(sp != NULL && *sp == NULL); + + s = isc_mem_get(mctx, sizeof(*s)); + if (s == NULL) + return (ISC_R_NOMEMORY); + s->common.mctx = mctx; + s->common.methods = &axfr_rrstream_methods; + s->it_valid = ISC_FALSE; + + CHECK(db_rr_iterator_init(&s->it, db, ver, 0)); + s->it_valid = ISC_TRUE; + + *sp = (rrstream_t *) s; + return (ISC_R_SUCCESS); + + failure: + axfr_rrstream_destroy((rrstream_t **) (void *)&s); + return (result); +} + +static isc_result_t +axfr_rrstream_first(rrstream_t *rs) { + axfr_rrstream_t *s = (axfr_rrstream_t *) rs; + isc_result_t result; + result = db_rr_iterator_first(&s->it); + if (result != ISC_R_SUCCESS) + return (result); + /* Skip SOA records. */ + for (;;) { + dns_name_t *name_dummy = NULL; + isc_uint32_t ttl_dummy; + dns_rdata_t *rdata = NULL; + db_rr_iterator_current(&s->it, &name_dummy, + &ttl_dummy, &rdata); + if (rdata->type != dns_rdatatype_soa) + break; + result = db_rr_iterator_next(&s->it); + if (result != ISC_R_SUCCESS) + break; + } + return (result); +} + +static isc_result_t +axfr_rrstream_next(rrstream_t *rs) { + axfr_rrstream_t *s = (axfr_rrstream_t *) rs; + isc_result_t result; + + /* Skip SOA records. */ + for (;;) { + dns_name_t *name_dummy = NULL; + isc_uint32_t ttl_dummy; + dns_rdata_t *rdata = NULL; + result = db_rr_iterator_next(&s->it); + if (result != ISC_R_SUCCESS) + break; + db_rr_iterator_current(&s->it, &name_dummy, + &ttl_dummy, &rdata); + if (rdata->type != dns_rdatatype_soa) + break; + } + return (result); +} + +static void +axfr_rrstream_current(rrstream_t *rs, dns_name_t **name, isc_uint32_t *ttl, + dns_rdata_t **rdata) +{ + axfr_rrstream_t *s = (axfr_rrstream_t *) rs; + db_rr_iterator_current(&s->it, name, ttl, rdata); +} + +static void +axfr_rrstream_pause(rrstream_t *rs) { + axfr_rrstream_t *s = (axfr_rrstream_t *) rs; + db_rr_iterator_pause(&s->it); +} + +static void +axfr_rrstream_destroy(rrstream_t **rsp) { + axfr_rrstream_t *s = (axfr_rrstream_t *) *rsp; + if (s->it_valid) + db_rr_iterator_destroy(&s->it); + isc_mem_put(s->common.mctx, s, sizeof(*s)); +} + +static rrstream_methods_t axfr_rrstream_methods = { + axfr_rrstream_first, + axfr_rrstream_next, + axfr_rrstream_current, + axfr_rrstream_pause, + axfr_rrstream_destroy +}; + +/**************************************************************************/ +/* + * An 'soa_rrstream_t' is a degenerate 'rrstream_t' that returns + * a single SOA record. + */ + +typedef struct soa_rrstream { + rrstream_t common; + dns_difftuple_t *soa_tuple; +} soa_rrstream_t; + +/* + * Forward declarations. + */ +static void +soa_rrstream_destroy(rrstream_t **rsp); + +static rrstream_methods_t soa_rrstream_methods; + +static isc_result_t +soa_rrstream_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *ver, + rrstream_t **sp) +{ + soa_rrstream_t *s; + isc_result_t result; + + INSIST(sp != NULL && *sp == NULL); + + s = isc_mem_get(mctx, sizeof(*s)); + if (s == NULL) + return (ISC_R_NOMEMORY); + s->common.mctx = mctx; + s->common.methods = &soa_rrstream_methods; + s->soa_tuple = NULL; + + CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_EXISTS, + &s->soa_tuple)); + + *sp = (rrstream_t *) s; + return (ISC_R_SUCCESS); + + failure: + soa_rrstream_destroy((rrstream_t **) (void *)&s); + return (result); +} + +static isc_result_t +soa_rrstream_first(rrstream_t *rs) { + UNUSED(rs); + return (ISC_R_SUCCESS); +} + +static isc_result_t +soa_rrstream_next(rrstream_t *rs) { + UNUSED(rs); + return (ISC_R_NOMORE); +} + +static void +soa_rrstream_current(rrstream_t *rs, dns_name_t **name, isc_uint32_t *ttl, + dns_rdata_t **rdata) +{ + soa_rrstream_t *s = (soa_rrstream_t *) rs; + *name = &s->soa_tuple->name; + *ttl = s->soa_tuple->ttl; + *rdata = &s->soa_tuple->rdata; +} + +static void +soa_rrstream_destroy(rrstream_t **rsp) { + soa_rrstream_t *s = (soa_rrstream_t *) *rsp; + if (s->soa_tuple != NULL) + dns_difftuple_free(&s->soa_tuple); + isc_mem_put(s->common.mctx, s, sizeof(*s)); +} + +static rrstream_methods_t soa_rrstream_methods = { + soa_rrstream_first, + soa_rrstream_next, + soa_rrstream_current, + rrstream_noop_pause, + soa_rrstream_destroy +}; + +/**************************************************************************/ +/* + * A 'compound_rrstream_t' objects owns a soa_rrstream + * and another rrstream, the "data stream". It returns + * a concatenated stream consisting of the soa_rrstream, then + * the data stream, then the soa_rrstream again. + * + * The component streams are owned by the compound_rrstream_t + * and are destroyed with it. + */ + +typedef struct compound_rrstream { + rrstream_t common; + rrstream_t *components[3]; + int state; + isc_result_t result; +} compound_rrstream_t; + +/* + * Forward declarations. + */ +static void +compound_rrstream_destroy(rrstream_t **rsp); + +static isc_result_t +compound_rrstream_next(rrstream_t *rs); + +static rrstream_methods_t compound_rrstream_methods; + +/* + * Requires: + * soa_stream != NULL && *soa_stream != NULL + * data_stream != NULL && *data_stream != NULL + * sp != NULL && *sp == NULL + * + * Ensures: + * *soa_stream == NULL + * *data_stream == NULL + * *sp points to a valid compound_rrstream_t + * The soa and data streams will be destroyed + * when the compound_rrstream_t is destroyed. + */ +static isc_result_t +compound_rrstream_create(isc_mem_t *mctx, rrstream_t **soa_stream, + rrstream_t **data_stream, rrstream_t **sp) +{ + compound_rrstream_t *s; + + INSIST(sp != NULL && *sp == NULL); + + s = isc_mem_get(mctx, sizeof(*s)); + if (s == NULL) + return (ISC_R_NOMEMORY); + s->common.mctx = mctx; + s->common.methods = &compound_rrstream_methods; + s->components[0] = *soa_stream; + s->components[1] = *data_stream; + s->components[2] = *soa_stream; + s->state = -1; + s->result = ISC_R_FAILURE; + + *soa_stream = NULL; + *data_stream = NULL; + *sp = (rrstream_t *) s; + return (ISC_R_SUCCESS); +} + +static isc_result_t +compound_rrstream_first(rrstream_t *rs) { + compound_rrstream_t *s = (compound_rrstream_t *) rs; + s->state = 0; + do { + rrstream_t *curstream = s->components[s->state]; + s->result = curstream->methods->first(curstream); + } while (s->result == ISC_R_NOMORE && s->state < 2); + return (s->result); +} + +static isc_result_t +compound_rrstream_next(rrstream_t *rs) { + compound_rrstream_t *s = (compound_rrstream_t *) rs; + rrstream_t *curstream = s->components[s->state]; + s->result = curstream->methods->next(curstream); + while (s->result == ISC_R_NOMORE) { + /* + * Make sure locks held by the current stream + * are released before we switch streams. + */ + curstream->methods->pause(curstream); + if (s->state == 2) + return (ISC_R_NOMORE); + s->state++; + curstream = s->components[s->state]; + s->result = curstream->methods->first(curstream); + } + return (s->result); +} + +static void +compound_rrstream_current(rrstream_t *rs, dns_name_t **name, isc_uint32_t *ttl, + dns_rdata_t **rdata) +{ + compound_rrstream_t *s = (compound_rrstream_t *) rs; + rrstream_t *curstream; + INSIST(0 <= s->state && s->state < 3); + INSIST(s->result == ISC_R_SUCCESS); + curstream = s->components[s->state]; + curstream->methods->current(curstream, name, ttl, rdata); +} + +static void +compound_rrstream_pause(rrstream_t *rs) +{ + compound_rrstream_t *s = (compound_rrstream_t *) rs; + rrstream_t *curstream; + INSIST(0 <= s->state && s->state < 3); + curstream = s->components[s->state]; + curstream->methods->pause(curstream); +} + +static void +compound_rrstream_destroy(rrstream_t **rsp) { + compound_rrstream_t *s = (compound_rrstream_t *) *rsp; + s->components[0]->methods->destroy(&s->components[0]); + s->components[1]->methods->destroy(&s->components[1]); + s->components[2] = NULL; /* Copy of components[0]. */ + isc_mem_put(s->common.mctx, s, sizeof(*s)); +} + +static rrstream_methods_t compound_rrstream_methods = { + compound_rrstream_first, + compound_rrstream_next, + compound_rrstream_current, + compound_rrstream_pause, + compound_rrstream_destroy +}; + +/**************************************************************************/ +/* + * An 'xfrout_ctx_t' contains the state of an outgoing AXFR or IXFR + * in progress. + */ + +typedef struct { + isc_mem_t *mctx; + ns_client_t *client; + unsigned int id; /* ID of request */ + dns_name_t *qname; /* Question name of request */ + dns_rdatatype_t qtype; /* dns_rdatatype_{a,i}xfr */ + dns_rdataclass_t qclass; + dns_zone_t *zone; /* (necessary for stats) */ + dns_db_t *db; + dns_dbversion_t *ver; + isc_quota_t *quota; + rrstream_t *stream; /* The XFR RR stream */ + isc_boolean_t end_of_stream; /* EOS has been reached */ + isc_buffer_t buf; /* Buffer for message owner + names and rdatas */ + isc_buffer_t txlenbuf; /* Transmit length buffer */ + isc_buffer_t txbuf; /* Transmit message buffer */ + void *txmem; + unsigned int txmemlen; + unsigned int nmsg; /* Number of messages sent */ + dns_tsigkey_t *tsigkey; /* Key used to create TSIG */ + isc_buffer_t *lasttsig; /* the last TSIG */ + isc_boolean_t many_answers; + int sends; /* Send in progress */ + isc_boolean_t shuttingdown; + const char *mnemonic; /* Style of transfer */ +} xfrout_ctx_t; + +static isc_result_t +xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, + unsigned int id, dns_name_t *qname, dns_rdatatype_t qtype, + dns_rdataclass_t qclass, dns_zone_t *zone, + dns_db_t *db, dns_dbversion_t *ver, isc_quota_t *quota, + rrstream_t *stream, dns_tsigkey_t *tsigkey, + isc_buffer_t *lasttsig, + unsigned int maxtime, + unsigned int idletime, + isc_boolean_t many_answers, + xfrout_ctx_t **xfrp); + +static void +sendstream(xfrout_ctx_t *xfr); + +static void +xfrout_senddone(isc_task_t *task, isc_event_t *event); + +static void +xfrout_fail(xfrout_ctx_t *xfr, isc_result_t result, const char *msg); + +static void +xfrout_maybe_destroy(xfrout_ctx_t *xfr); + +static void +xfrout_ctx_destroy(xfrout_ctx_t **xfrp); + +static void +xfrout_client_shutdown(void *arg, isc_result_t result); + +static void +xfrout_log1(ns_client_t *client, dns_name_t *zonename, + dns_rdataclass_t rdclass, int level, + const char *fmt, ...) ISC_FORMAT_PRINTF(5, 6); + +static void +xfrout_log(xfrout_ctx_t *xfr, int level, const char *fmt, ...) + ISC_FORMAT_PRINTF(3, 4); + +/**************************************************************************/ + +void +ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) { + isc_result_t result; + dns_name_t *question_name; + dns_rdataset_t *question_rdataset; + dns_zone_t *zone = NULL; + dns_db_t *db = NULL; + dns_dbversion_t *ver = NULL; + dns_rdataclass_t question_class; + rrstream_t *soa_stream = NULL; + rrstream_t *data_stream = NULL; + rrstream_t *stream = NULL; + dns_difftuple_t *current_soa_tuple = NULL; + dns_name_t *soa_name; + dns_rdataset_t *soa_rdataset; + dns_rdata_t soa_rdata = DNS_RDATA_INIT; + isc_boolean_t have_soa = ISC_FALSE; + const char *mnemonic = NULL; + isc_mem_t *mctx = client->mctx; + dns_message_t *request = client->message; + xfrout_ctx_t *xfr = NULL; + isc_quota_t *quota = NULL; + dns_transfer_format_t format = client->view->transfer_format; + isc_netaddr_t na; + dns_peer_t *peer = NULL; + isc_buffer_t *tsigbuf = NULL; + char *journalfile; + char msg[NS_CLIENT_ACLMSGSIZE("zone transfer")]; + char keyname[DNS_NAME_FORMATSIZE]; + isc_boolean_t is_poll = ISC_FALSE; +#ifdef DLZ + isc_boolean_t is_dlz = ISC_FALSE; +#endif + + switch (reqtype) { + case dns_rdatatype_axfr: + mnemonic = "AXFR"; + break; + case dns_rdatatype_ixfr: + mnemonic = "IXFR"; + break; + default: + INSIST(0); + break; + } + + ns_client_log(client, + DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT, + ISC_LOG_DEBUG(6), "%s request", mnemonic); + /* + * Apply quota. + */ + result = isc_quota_attach(&ns_g_server->xfroutquota, "a); + if (result != ISC_R_SUCCESS) { + isc_log_write(XFROUT_COMMON_LOGARGS, ISC_LOG_WARNING, + "%s request denied: %s", mnemonic, + isc_result_totext(result)); + goto failure; + } + + /* + * Interpret the question section. + */ + result = dns_message_firstname(request, DNS_SECTION_QUESTION); + INSIST(result == ISC_R_SUCCESS); + + /* + * The question section must contain exactly one question, and + * it must be for AXFR/IXFR as appropriate. + */ + question_name = NULL; + dns_message_currentname(request, DNS_SECTION_QUESTION, &question_name); + question_rdataset = ISC_LIST_HEAD(question_name->list); + question_class = question_rdataset->rdclass; + INSIST(question_rdataset->type == reqtype); + if (ISC_LIST_NEXT(question_rdataset, link) != NULL) + FAILC(DNS_R_FORMERR, "multiple questions"); + result = dns_message_nextname(request, DNS_SECTION_QUESTION); + if (result != ISC_R_NOMORE) + FAILC(DNS_R_FORMERR, "multiple questions"); + + result = dns_zt_find(client->view->zonetable, question_name, 0, NULL, + &zone); + + if (result != ISC_R_SUCCESS) +#ifdef DLZ + { + /* + * Normal zone table does not have a match. Try the DLZ database + */ + if (client->view->dlzdatabase != NULL) { + result = dns_dlzallowzonexfr(client->view, + question_name, &client->peeraddr, + &db); + + if (result == ISC_R_NOPERM) { + char _buf1[DNS_NAME_FORMATSIZE]; + char _buf2[DNS_RDATACLASS_FORMATSIZE]; + + result = DNS_R_REFUSED; + dns_name_format(question_name, _buf1, + sizeof(_buf1)); + dns_rdataclass_format(question_class, + _buf2, sizeof(_buf2)); + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_XFER_OUT, + ISC_LOG_ERROR, + "zone transfer '%s/%s' denied", + _buf1, _buf2); + goto failure; + } + if (result != ISC_R_SUCCESS) +#endif + FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", + question_name, question_class); +#ifdef DLZ + is_dlz = ISC_TRUE; + /* + * DLZ only support full zone transfer, not incremental + */ + if (reqtype != dns_rdatatype_axfr) { + mnemonic = "AXFR-style IXFR"; + reqtype = dns_rdatatype_axfr; + } + + } else { + /* + * not DLZ and not in normal zone table, we are + * not authoritative + */ + FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", + question_name, question_class); + } + } else { + /* zone table has a match */ +#endif + switch(dns_zone_gettype(zone)) { + case dns_zone_master: + case dns_zone_slave: + break; /* Master and slave zones are OK for transfer. */ + default: + FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", question_name, question_class); + } + CHECK(dns_zone_getdb(zone, &db)); + dns_db_currentversion(db, &ver); +#ifdef DLZ + } +#endif + + xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6), + "%s question section OK", mnemonic); + + /* + * Check the authority section. Look for a SOA record with + * the same name and class as the question. + */ + for (result = dns_message_firstname(request, DNS_SECTION_AUTHORITY); + result == ISC_R_SUCCESS; + result = dns_message_nextname(request, DNS_SECTION_AUTHORITY)) + { + soa_name = NULL; + dns_message_currentname(request, DNS_SECTION_AUTHORITY, + &soa_name); + + /* + * Ignore data whose owner name is not the zone apex. + */ + if (! dns_name_equal(soa_name, question_name)) + continue; + + for (soa_rdataset = ISC_LIST_HEAD(soa_name->list); + soa_rdataset != NULL; + soa_rdataset = ISC_LIST_NEXT(soa_rdataset, link)) + { + /* + * Ignore non-SOA data. + */ + if (soa_rdataset->type != dns_rdatatype_soa) + continue; + if (soa_rdataset->rdclass != question_class) + continue; + + CHECK(dns_rdataset_first(soa_rdataset)); + dns_rdataset_current(soa_rdataset, &soa_rdata); + result = dns_rdataset_next(soa_rdataset); + if (result == ISC_R_SUCCESS) + FAILC(DNS_R_FORMERR, + "IXFR authority section " + "has multiple SOAs"); + have_soa = ISC_TRUE; + goto got_soa; + } + } + got_soa: + if (result != ISC_R_NOMORE) + CHECK(result); + + xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6), + "%s authority section OK", mnemonic); + + /* + * Decide whether to allow this transfer. + */ +#ifdef DLZ + /* + * if not a DLZ zone decide whether to allow this transfer. + */ + if (!is_dlz) { +#endif + ns_client_aclmsg("zone transfer", question_name, reqtype, + client->view->rdclass, msg, sizeof(msg)); + CHECK(ns_client_checkacl(client, NULL, msg, + dns_zone_getxfracl(zone), + ISC_TRUE, ISC_LOG_ERROR)); +#ifdef DLZ + } +#endif + + /* + * AXFR over UDP is not possible. + */ + if (reqtype == dns_rdatatype_axfr && + (client->attributes & NS_CLIENTATTR_TCP) == 0) + FAILC(DNS_R_FORMERR, "attempted AXFR over UDP"); + + /* + * Look up the requesting server in the peer table. + */ + isc_netaddr_fromsockaddr(&na, &client->peeraddr); + (void)dns_peerlist_peerbyaddr(client->view->peers, &na, &peer); + + /* + * Decide on the transfer format (one-answer or many-answers). + */ + if (peer != NULL) + (void)dns_peer_gettransferformat(peer, &format); + + /* + * Get a dynamically allocated copy of the current SOA. + */ +#ifdef DLZ + if (is_dlz) + dns_db_currentversion(db, &ver); +#endif + CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_EXISTS, + ¤t_soa_tuple)); + + if (reqtype == dns_rdatatype_ixfr) { + isc_uint32_t begin_serial, current_serial; + isc_boolean_t provide_ixfr; + + /* + * Outgoing IXFR may have been disabled for this peer + * or globally. + */ + provide_ixfr = client->view->provideixfr; + if (peer != NULL) + (void) dns_peer_getprovideixfr(peer, &provide_ixfr); + if (provide_ixfr == ISC_FALSE) + goto axfr_fallback; + + if (! have_soa) + FAILC(DNS_R_FORMERR, + "IXFR request missing SOA"); + + begin_serial = dns_soa_getserial(&soa_rdata); + current_serial = dns_soa_getserial(¤t_soa_tuple->rdata); + + /* + * RFC1995 says "If an IXFR query with the same or + * newer version number than that of the server + * is received, it is replied to with a single SOA + * record of the server's current version, just as + * in AXFR". The claim about AXFR is incorrect, + * but other than that, we do as the RFC says. + * + * Sending a single SOA record is also how we refuse + * IXFR over UDP (currently, we always do). + */ + if (DNS_SERIAL_GE(begin_serial, current_serial) || + (client->attributes & NS_CLIENTATTR_TCP) == 0) + { + CHECK(soa_rrstream_create(mctx, db, ver, &stream)); + is_poll = ISC_TRUE; + goto have_stream; + } + journalfile = dns_zone_getjournal(zone); + if (journalfile != NULL) + result = ixfr_rrstream_create(mctx, + journalfile, + begin_serial, + current_serial, + &data_stream); + else + result = ISC_R_NOTFOUND; + if (result == ISC_R_NOTFOUND || + result == ISC_R_RANGE) { + xfrout_log1(client, question_name, question_class, + ISC_LOG_DEBUG(4), + "IXFR version not in journal, " + "falling back to AXFR"); + mnemonic = "AXFR-style IXFR"; + goto axfr_fallback; + } + CHECK(result); + } else { + axfr_fallback: + CHECK(axfr_rrstream_create(mctx, db, ver, + &data_stream)); + } + + /* + * Bracket the data stream with SOAs. + */ + CHECK(soa_rrstream_create(mctx, db, ver, &soa_stream)); + CHECK(compound_rrstream_create(mctx, &soa_stream, &data_stream, + &stream)); + soa_stream = NULL; + data_stream = NULL; + + have_stream: + CHECK(dns_message_getquerytsig(request, mctx, &tsigbuf)); + /* + * Create the xfrout context object. This transfers the ownership + * of "stream", "db", "ver", and "quota" to the xfrout context object. + */ + + + +#ifdef DLZ + if (is_dlz) + CHECK(xfrout_ctx_create(mctx, client, request->id, question_name, + reqtype, question_class, zone, db, ver, + quota, stream, + dns_message_gettsigkey(request), + tsigbuf, + 3600, + 3600, + (format == dns_many_answers) ? + ISC_TRUE : ISC_FALSE, + &xfr)); + else +#endif + CHECK(xfrout_ctx_create(mctx, client, request->id, question_name, + reqtype, question_class, zone, db, ver, + quota, stream, + dns_message_gettsigkey(request), + tsigbuf, + dns_zone_getmaxxfrout(zone), + dns_zone_getidleout(zone), + (format == dns_many_answers) ? + ISC_TRUE : ISC_FALSE, + &xfr)); + + xfr->mnemonic = mnemonic; + stream = NULL; + quota = NULL; + + CHECK(xfr->stream->methods->first(xfr->stream)); + + if (xfr->tsigkey != NULL) { + dns_name_format(&xfr->tsigkey->name, keyname, sizeof(keyname)); + } else + keyname[0] = '\0'; + if (is_poll) + xfrout_log1(client, question_name, question_class, + ISC_LOG_DEBUG(1), "IXFR poll up to date%s%s", + (xfr->tsigkey != NULL) ? ": TSIG " : "", keyname); + else + xfrout_log1(client, question_name, question_class, + ISC_LOG_INFO, "%s started%s%s", mnemonic, + (xfr->tsigkey != NULL) ? ": TSIG " : "", keyname); + + /* + * Hand the context over to sendstream(). Set xfr to NULL; + * sendstream() is responsible for either passing the + * context on to a later event handler or destroying it. + */ + sendstream(xfr); + xfr = NULL; + + result = ISC_R_SUCCESS; + + failure: + if (result == DNS_R_REFUSED) + inc_stats(zone, dns_nsstatscounter_xfrrej); + if (quota != NULL) + isc_quota_detach("a); + if (current_soa_tuple != NULL) + dns_difftuple_free(¤t_soa_tuple); + if (stream != NULL) + stream->methods->destroy(&stream); + if (soa_stream != NULL) + soa_stream->methods->destroy(&soa_stream); + if (data_stream != NULL) + data_stream->methods->destroy(&data_stream); + if (ver != NULL) + dns_db_closeversion(db, &ver, ISC_FALSE); + if (db != NULL) + dns_db_detach(&db); + if (zone != NULL) + dns_zone_detach(&zone); + /* XXX kludge */ + if (xfr != NULL) { + xfrout_fail(xfr, result, "setting up zone transfer"); + } else if (result != ISC_R_SUCCESS) { + ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, + NS_LOGMODULE_XFER_OUT, + ISC_LOG_DEBUG(3), "zone transfer setup failed"); + ns_client_error(client, result); + } +} + +static isc_result_t +xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id, + dns_name_t *qname, dns_rdatatype_t qtype, + dns_rdataclass_t qclass, dns_zone_t *zone, + dns_db_t *db, dns_dbversion_t *ver, isc_quota_t *quota, + rrstream_t *stream, dns_tsigkey_t *tsigkey, + isc_buffer_t *lasttsig, unsigned int maxtime, + unsigned int idletime, isc_boolean_t many_answers, + xfrout_ctx_t **xfrp) +{ + xfrout_ctx_t *xfr; + isc_result_t result; + unsigned int len; + void *mem; + + INSIST(xfrp != NULL && *xfrp == NULL); + xfr = isc_mem_get(mctx, sizeof(*xfr)); + if (xfr == NULL) + return (ISC_R_NOMEMORY); + xfr->mctx = mctx; + xfr->client = NULL; + ns_client_attach(client, &xfr->client); + xfr->id = id; + xfr->qname = qname; + xfr->qtype = qtype; + xfr->qclass = qclass; + xfr->zone = NULL; + xfr->db = NULL; + xfr->ver = NULL; + if (zone != NULL) /* zone will be NULL if it's DLZ */ + dns_zone_attach(zone, &xfr->zone); + dns_db_attach(db, &xfr->db); + dns_db_attachversion(db, ver, &xfr->ver); + xfr->end_of_stream = ISC_FALSE; + xfr->tsigkey = tsigkey; + xfr->lasttsig = lasttsig; + xfr->txmem = NULL; + xfr->txmemlen = 0; + xfr->nmsg = 0; + xfr->many_answers = many_answers, + xfr->sends = 0; + xfr->shuttingdown = ISC_FALSE; + xfr->mnemonic = NULL; + xfr->buf.base = NULL; + xfr->buf.length = 0; + xfr->txmem = NULL; + xfr->txmemlen = 0; + xfr->stream = NULL; + xfr->quota = NULL; + + /* + * Allocate a temporary buffer for the uncompressed response + * message data. The size should be no more than 65535 bytes + * so that the compressed data will fit in a TCP message, + * and no less than 65535 bytes so that an almost maximum-sized + * RR will fit. Note that although 65535-byte RRs are allowed + * in principle, they cannot be zone-transferred (at least not + * if uncompressible), because the message and RR headers would + * push the size of the TCP message over the 65536 byte limit. + */ + len = 65535; + mem = isc_mem_get(mctx, len); + if (mem == NULL) { + result = ISC_R_NOMEMORY; + goto failure; + } + isc_buffer_init(&xfr->buf, mem, len); + + /* + * Allocate another temporary buffer for the compressed + * response message and its TCP length prefix. + */ + len = 2 + 65535; + mem = isc_mem_get(mctx, len); + if (mem == NULL) { + result = ISC_R_NOMEMORY; + goto failure; + } + isc_buffer_init(&xfr->txlenbuf, mem, 2); + isc_buffer_init(&xfr->txbuf, (char *) mem + 2, len - 2); + xfr->txmem = mem; + xfr->txmemlen = len; + + CHECK(dns_timer_setidle(xfr->client->timer, + maxtime, idletime, ISC_FALSE)); + + /* + * Register a shutdown callback with the client, so that we + * can stop the transfer immediately when the client task + * gets a shutdown event. + */ + xfr->client->shutdown = xfrout_client_shutdown; + xfr->client->shutdown_arg = xfr; + /* + * These MUST be after the last "goto failure;" / CHECK to + * prevent a double free by the caller. + */ + xfr->quota = quota; + xfr->stream = stream; + + *xfrp = xfr; + return (ISC_R_SUCCESS); + +failure: + xfrout_ctx_destroy(&xfr); + return (result); +} + + +/* + * Arrange to send as much as we can of "stream" without blocking. + * + * Requires: + * The stream iterator is initialized and points at an RR, + * or possibly at the end of the stream (that is, the + * _first method of the iterator has been called). + */ +static void +sendstream(xfrout_ctx_t *xfr) { + dns_message_t *tcpmsg = NULL; + dns_message_t *msg = NULL; /* Client message if UDP, tcpmsg if TCP */ + isc_result_t result; + isc_region_t used; + isc_region_t region; + dns_rdataset_t *qrdataset; + dns_name_t *msgname = NULL; + dns_rdata_t *msgrdata = NULL; + dns_rdatalist_t *msgrdl = NULL; + dns_rdataset_t *msgrds = NULL; + dns_compress_t cctx; + isc_boolean_t cleanup_cctx = ISC_FALSE; + + int n_rrs; + + isc_buffer_clear(&xfr->buf); + isc_buffer_clear(&xfr->txlenbuf); + isc_buffer_clear(&xfr->txbuf); + + if ((xfr->client->attributes & NS_CLIENTATTR_TCP) == 0) { + /* + * In the UDP case, we put the response data directly into + * the client message. + */ + msg = xfr->client->message; + CHECK(dns_message_reply(msg, ISC_TRUE)); + } else { + /* + * TCP. Build a response dns_message_t, temporarily storing + * the raw, uncompressed owner names and RR data contiguously + * in xfr->buf. We know that if the uncompressed data fits + * in xfr->buf, the compressed data will surely fit in a TCP + * message. + */ + + CHECK(dns_message_create(xfr->mctx, + DNS_MESSAGE_INTENTRENDER, &tcpmsg)); + msg = tcpmsg; + + msg->id = xfr->id; + msg->rcode = dns_rcode_noerror; + msg->flags = DNS_MESSAGEFLAG_QR | DNS_MESSAGEFLAG_AA; + if ((xfr->client->attributes & NS_CLIENTATTR_RA) != 0) + msg->flags |= DNS_MESSAGEFLAG_RA; + CHECK(dns_message_settsigkey(msg, xfr->tsigkey)); + CHECK(dns_message_setquerytsig(msg, xfr->lasttsig)); + if (xfr->lasttsig != NULL) + isc_buffer_free(&xfr->lasttsig); + + /* + * Include a question section in the first message only. + * BIND 8.2.1 will not recognize an IXFR if it does not + * have a question section. + */ + if (xfr->nmsg == 0) { + dns_name_t *qname = NULL; + isc_region_t r; + + /* + * Reserve space for the 12-byte message header + * and 4 bytes of question. + */ + isc_buffer_add(&xfr->buf, 12 + 4); + + qrdataset = NULL; + result = dns_message_gettemprdataset(msg, &qrdataset); + if (result != ISC_R_SUCCESS) + goto failure; + dns_rdataset_init(qrdataset); + dns_rdataset_makequestion(qrdataset, + xfr->client->message->rdclass, + xfr->qtype); + + result = dns_message_gettempname(msg, &qname); + if (result != ISC_R_SUCCESS) + goto failure; + dns_name_init(qname, NULL); + isc_buffer_availableregion(&xfr->buf, &r); + INSIST(r.length >= xfr->qname->length); + r.length = xfr->qname->length; + isc_buffer_putmem(&xfr->buf, xfr->qname->ndata, + xfr->qname->length); + dns_name_fromregion(qname, &r); + ISC_LIST_INIT(qname->list); + ISC_LIST_APPEND(qname->list, qrdataset, link); + + dns_message_addname(msg, qname, DNS_SECTION_QUESTION); + } + else + msg->tcp_continuation = 1; + } + + /* + * Try to fit in as many RRs as possible, unless "one-answer" + * format has been requested. + */ + for (n_rrs = 0; ; n_rrs++) { + dns_name_t *name = NULL; + isc_uint32_t ttl; + dns_rdata_t *rdata = NULL; + + unsigned int size; + isc_region_t r; + + msgname = NULL; + msgrdata = NULL; + msgrdl = NULL; + msgrds = NULL; + + xfr->stream->methods->current(xfr->stream, + &name, &ttl, &rdata); + size = name->length + 10 + rdata->length; + isc_buffer_availableregion(&xfr->buf, &r); + if (size >= r.length) { + /* + * RR would not fit. If there are other RRs in the + * buffer, send them now and leave this RR to the + * next message. If this RR overflows the buffer + * all by itself, fail. + * + * In theory some RRs might fit in a TCP message + * when compressed even if they do not fit when + * uncompressed, but surely we don't want + * to send such monstrosities to an unsuspecting + * slave. + */ + if (n_rrs == 0) { + xfrout_log(xfr, ISC_LOG_WARNING, + "RR too large for zone transfer " + "(%d bytes)", size); + /* XXX DNS_R_RRTOOLARGE? */ + result = ISC_R_NOSPACE; + goto failure; + } + break; + } + + if (isc_log_wouldlog(ns_g_lctx, XFROUT_RR_LOGLEVEL)) + log_rr(name, rdata, ttl); /* XXX */ + + result = dns_message_gettempname(msg, &msgname); + if (result != ISC_R_SUCCESS) + goto failure; + dns_name_init(msgname, NULL); + isc_buffer_availableregion(&xfr->buf, &r); + INSIST(r.length >= name->length); + r.length = name->length; + isc_buffer_putmem(&xfr->buf, name->ndata, name->length); + dns_name_fromregion(msgname, &r); + + /* Reserve space for RR header. */ + isc_buffer_add(&xfr->buf, 10); + + result = dns_message_gettemprdata(msg, &msgrdata); + if (result != ISC_R_SUCCESS) + goto failure; + isc_buffer_availableregion(&xfr->buf, &r); + r.length = rdata->length; + isc_buffer_putmem(&xfr->buf, rdata->data, rdata->length); + dns_rdata_init(msgrdata); + dns_rdata_fromregion(msgrdata, + rdata->rdclass, rdata->type, &r); + + result = dns_message_gettemprdatalist(msg, &msgrdl); + if (result != ISC_R_SUCCESS) + goto failure; + msgrdl->type = rdata->type; + msgrdl->rdclass = rdata->rdclass; + msgrdl->ttl = ttl; + if (rdata->type == dns_rdatatype_sig || + rdata->type == dns_rdatatype_rrsig) + msgrdl->covers = dns_rdata_covers(rdata); + else + msgrdl->covers = dns_rdatatype_none; + ISC_LINK_INIT(msgrdl, link); + ISC_LIST_INIT(msgrdl->rdata); + ISC_LIST_APPEND(msgrdl->rdata, msgrdata, link); + + result = dns_message_gettemprdataset(msg, &msgrds); + if (result != ISC_R_SUCCESS) + goto failure; + dns_rdataset_init(msgrds); + result = dns_rdatalist_tordataset(msgrdl, msgrds); + INSIST(result == ISC_R_SUCCESS); + + ISC_LIST_APPEND(msgname->list, msgrds, link); + + dns_message_addname(msg, msgname, DNS_SECTION_ANSWER); + msgname = NULL; + + result = xfr->stream->methods->next(xfr->stream); + if (result == ISC_R_NOMORE) { + xfr->end_of_stream = ISC_TRUE; + break; + } + CHECK(result); + + if (! xfr->many_answers) + break; + } + + if ((xfr->client->attributes & NS_CLIENTATTR_TCP) != 0) { + CHECK(dns_compress_init(&cctx, -1, xfr->mctx)); + dns_compress_setsensitive(&cctx, ISC_TRUE); + cleanup_cctx = ISC_TRUE; + CHECK(dns_message_renderbegin(msg, &cctx, &xfr->txbuf)); + CHECK(dns_message_rendersection(msg, DNS_SECTION_QUESTION, 0)); + CHECK(dns_message_rendersection(msg, DNS_SECTION_ANSWER, 0)); + CHECK(dns_message_renderend(msg)); + dns_compress_invalidate(&cctx); + cleanup_cctx = ISC_FALSE; + + isc_buffer_usedregion(&xfr->txbuf, &used); + isc_buffer_putuint16(&xfr->txlenbuf, + (isc_uint16_t)used.length); + region.base = xfr->txlenbuf.base; + region.length = 2 + used.length; + xfrout_log(xfr, ISC_LOG_DEBUG(8), + "sending TCP message of %d bytes", + used.length); + CHECK(isc_socket_send(xfr->client->tcpsocket, /* XXX */ + ®ion, xfr->client->task, + xfrout_senddone, + xfr)); + xfr->sends++; + } else { + xfrout_log(xfr, ISC_LOG_DEBUG(8), "sending IXFR UDP response"); + ns_client_send(xfr->client); + xfr->stream->methods->pause(xfr->stream); + xfrout_ctx_destroy(&xfr); + return; + } + + /* Advance lasttsig to be the last TSIG generated */ + CHECK(dns_message_getquerytsig(msg, xfr->mctx, &xfr->lasttsig)); + + xfr->nmsg++; + + failure: + if (msgname != NULL) { + if (msgrds != NULL) { + if (dns_rdataset_isassociated(msgrds)) + dns_rdataset_disassociate(msgrds); + dns_message_puttemprdataset(msg, &msgrds); + } + if (msgrdl != NULL) { + ISC_LIST_UNLINK(msgrdl->rdata, msgrdata, link); + dns_message_puttemprdatalist(msg, &msgrdl); + } + if (msgrdata != NULL) + dns_message_puttemprdata(msg, &msgrdata); + dns_message_puttempname(msg, &msgname); + } + + if (tcpmsg != NULL) + dns_message_destroy(&tcpmsg); + + if (cleanup_cctx) + dns_compress_invalidate(&cctx); + /* + * Make sure to release any locks held by database + * iterators before returning from the event handler. + */ + xfr->stream->methods->pause(xfr->stream); + + if (result == ISC_R_SUCCESS) + return; + + xfrout_fail(xfr, result, "sending zone data"); +} + +static void +xfrout_ctx_destroy(xfrout_ctx_t **xfrp) { + xfrout_ctx_t *xfr = *xfrp; + + INSIST(xfr->sends == 0); + + xfr->client->shutdown = NULL; + xfr->client->shutdown_arg = NULL; + + if (xfr->stream != NULL) + xfr->stream->methods->destroy(&xfr->stream); + if (xfr->buf.base != NULL) + isc_mem_put(xfr->mctx, xfr->buf.base, xfr->buf.length); + if (xfr->txmem != NULL) + isc_mem_put(xfr->mctx, xfr->txmem, xfr->txmemlen); + if (xfr->lasttsig != NULL) + isc_buffer_free(&xfr->lasttsig); + if (xfr->quota != NULL) + isc_quota_detach(&xfr->quota); + if (xfr->ver != NULL) + dns_db_closeversion(xfr->db, &xfr->ver, ISC_FALSE); + if (xfr->zone != NULL) + dns_zone_detach(&xfr->zone); + if (xfr->db != NULL) + dns_db_detach(&xfr->db); + + ns_client_detach(&xfr->client); + + isc_mem_put(xfr->mctx, xfr, sizeof(*xfr)); + + *xfrp = NULL; +} + +static void +xfrout_senddone(isc_task_t *task, isc_event_t *event) { + isc_socketevent_t *sev = (isc_socketevent_t *)event; + xfrout_ctx_t *xfr = (xfrout_ctx_t *)event->ev_arg; + isc_result_t evresult = sev->result; + + UNUSED(task); + + INSIST(event->ev_type == ISC_SOCKEVENT_SENDDONE); + + isc_event_free(&event); + xfr->sends--; + INSIST(xfr->sends == 0); + + (void)isc_timer_touch(xfr->client->timer); + if (xfr->shuttingdown == ISC_TRUE) { + xfrout_maybe_destroy(xfr); + } else if (evresult != ISC_R_SUCCESS) { + xfrout_fail(xfr, evresult, "send"); + } else if (xfr->end_of_stream == ISC_FALSE) { + sendstream(xfr); + } else { + /* End of zone transfer stream. */ + inc_stats(xfr->zone, dns_nsstatscounter_xfrdone); + xfrout_log(xfr, ISC_LOG_INFO, "%s ended", xfr->mnemonic); + ns_client_next(xfr->client, ISC_R_SUCCESS); + xfrout_ctx_destroy(&xfr); + } +} + +static void +xfrout_fail(xfrout_ctx_t *xfr, isc_result_t result, const char *msg) { + xfr->shuttingdown = ISC_TRUE; + xfrout_log(xfr, ISC_LOG_ERROR, "%s: %s", + msg, isc_result_totext(result)); + xfrout_maybe_destroy(xfr); +} + +static void +xfrout_maybe_destroy(xfrout_ctx_t *xfr) { + INSIST(xfr->shuttingdown == ISC_TRUE); + if (xfr->sends > 0) { + /* + * If we are currently sending, cancel it and wait for + * cancel event before destroying the context. + */ + isc_socket_cancel(xfr->client->tcpsocket, xfr->client->task, + ISC_SOCKCANCEL_SEND); + } else { + ns_client_next(xfr->client, ISC_R_CANCELED); + xfrout_ctx_destroy(&xfr); + } +} + +static void +xfrout_client_shutdown(void *arg, isc_result_t result) { + xfrout_ctx_t *xfr = (xfrout_ctx_t *) arg; + xfrout_fail(xfr, result, "aborted"); +} + +/* + * Log outgoing zone transfer messages in a format like + * : transfer of : + */ + +static void +xfrout_logv(ns_client_t *client, dns_name_t *zonename, + dns_rdataclass_t rdclass, int level, const char *fmt, va_list ap) + ISC_FORMAT_PRINTF(5, 0); + +static void +xfrout_logv(ns_client_t *client, dns_name_t *zonename, + dns_rdataclass_t rdclass, int level, const char *fmt, va_list ap) +{ + char msgbuf[2048]; + char namebuf[DNS_NAME_FORMATSIZE]; + char classbuf[DNS_RDATACLASS_FORMATSIZE]; + + dns_name_format(zonename, namebuf, sizeof(namebuf)); + dns_rdataclass_format(rdclass, classbuf, sizeof(classbuf)); + vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); + ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, + NS_LOGMODULE_XFER_OUT, level, + "transfer of '%s/%s': %s", namebuf, classbuf, msgbuf); +} + +/* + * Logging function for use when a xfrout_ctx_t has not yet been created. + */ +static void +xfrout_log1(ns_client_t *client, dns_name_t *zonename, + dns_rdataclass_t rdclass, int level, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + xfrout_logv(client, zonename, rdclass, level, fmt, ap); + va_end(ap); +} + +/* + * Logging function for use when there is a xfrout_ctx_t. + */ +static void +xfrout_log(xfrout_ctx_t *xfr, int level, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + xfrout_logv(xfr->client, xfr->qname, xfr->qclass, level, fmt, ap); + va_end(ap); +} diff --git a/contrib/bind-9.5.2/bin/named/zoneconf.c b/contrib/bind-9.5.2/bin/named/zoneconf.c new file mode 100644 index 0000000000..ea0b1de049 --- /dev/null +++ b/contrib/bind-9.5.2/bin/named/zoneconf.c @@ -0,0 +1,966 @@ +/* + * Copyright (C) 2004-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 + * 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: zoneconf.c,v 1.139.56.7 2009/01/29 23:47:13 tbox Exp $ */ + +/*% */ + +#include + +#include +#include +#include +#include +#include +#include /* Required for HP/UX (and others?) */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* ACLs associated with zone */ +typedef enum { + allow_notify, + allow_query, + allow_transfer, + allow_update, + allow_update_forwarding +} acl_type_t; + +/*% + * These are BIND9 server defaults, not necessarily identical to the + * library defaults defined in zone.c. + */ +#define RETERR(x) do { \ + isc_result_t _r = (x); \ + if (_r != ISC_R_SUCCESS) \ + return (_r); \ + } while (0) + +/*% + * Convenience function for configuring a single zone ACL. + */ +static isc_result_t +configure_zone_acl(const cfg_obj_t *zconfig, const cfg_obj_t *vconfig, + const cfg_obj_t *config, acl_type_t acltype, + cfg_aclconfctx_t *actx, dns_zone_t *zone, + void (*setzacl)(dns_zone_t *, dns_acl_t *), + void (*clearzacl)(dns_zone_t *)) +{ + isc_result_t result; + const cfg_obj_t *maps[5] = {NULL, NULL, NULL, NULL, NULL}; + const cfg_obj_t *aclobj = NULL; + int i = 0; + dns_acl_t **aclp = NULL, *acl = NULL; + const char *aclname; + dns_view_t *view; + + view = dns_zone_getview(zone); + + switch (acltype) { + case allow_notify: + if (view != NULL) + aclp = &view->notifyacl; + aclname = "allow-notify"; + break; + case allow_query: + if (view != NULL) + aclp = &view->queryacl; + aclname = "allow-query"; + break; + case allow_transfer: + if (view != NULL) + aclp = &view->transferacl; + aclname = "allow-transfer"; + break; + case allow_update: + if (view != NULL) + aclp = &view->updateacl; + aclname = "allow-update"; + break; + case allow_update_forwarding: + if (view != NULL) + aclp = &view->upfwdacl; + aclname = "allow-update-forwarding"; + break; + default: + INSIST(0); + return (ISC_R_FAILURE); + } + + /* First check to see if ACL is defined within the zone */ + if (zconfig != NULL) { + maps[0] = cfg_tuple_get(zconfig, "options"); + ns_config_get(maps, aclname, &aclobj); + if (aclobj != NULL) { + aclp = NULL; + goto parse_acl; + } + } + + /* Failing that, see if there's a default ACL already in the view */ + if (aclp != NULL && *aclp != NULL) { + (*setzacl)(zone, *aclp); + return (ISC_R_SUCCESS); + } + + /* Check for default ACLs that haven't been parsed yet */ + if (vconfig != NULL) + maps[i++] = cfg_tuple_get(vconfig, "options"); + if (config != NULL) { + const cfg_obj_t *options = NULL; + (void)cfg_map_get(config, "options", &options); + if (options != NULL) + maps[i++] = options; + } + maps[i++] = ns_g_defaults; + maps[i] = NULL; + + result = ns_config_get(maps, aclname, &aclobj); + if (aclobj == NULL) { + (*clearzacl)(zone); + return (ISC_R_SUCCESS); + } + +parse_acl: + result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx, actx, + dns_zone_getmctx(zone), 0, &acl); + if (result != ISC_R_SUCCESS) + return (result); + (*setzacl)(zone, acl); + + /* Set the view default now */ + if (aclp != NULL) + dns_acl_attach(acl, aclp); + + dns_acl_detach(&acl); + return (ISC_R_SUCCESS); +} + +/*% + * Parse the zone update-policy statement. + */ +static isc_result_t +configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone) { + const cfg_obj_t *updatepolicy = NULL; + const cfg_listelt_t *element, *element2; + dns_ssutable_t *table = NULL; + isc_mem_t *mctx = dns_zone_getmctx(zone); + isc_result_t result; + + (void)cfg_map_get(zconfig, "update-policy", &updatepolicy); + if (updatepolicy == NULL) { + dns_zone_setssutable(zone, NULL); + return (ISC_R_SUCCESS); + } + + result = dns_ssutable_create(mctx, &table); + if (result != ISC_R_SUCCESS) + return (result); + + for (element = cfg_list_first(updatepolicy); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *stmt = cfg_listelt_value(element); + const cfg_obj_t *mode = cfg_tuple_get(stmt, "mode"); + const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity"); + const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype"); + const cfg_obj_t *dname = cfg_tuple_get(stmt, "name"); + const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types"); + const char *str; + isc_boolean_t grant = ISC_FALSE; + unsigned int mtype = DNS_SSUMATCHTYPE_NAME; + dns_fixedname_t fname, fident; + isc_buffer_t b; + dns_rdatatype_t *types; + unsigned int i, n; + + str = cfg_obj_asstring(mode); + if (strcasecmp(str, "grant") == 0) + grant = ISC_TRUE; + else if (strcasecmp(str, "deny") == 0) + grant = ISC_FALSE; + else + INSIST(0); + + str = cfg_obj_asstring(matchtype); + if (strcasecmp(str, "name") == 0) + mtype = DNS_SSUMATCHTYPE_NAME; + else if (strcasecmp(str, "subdomain") == 0) + mtype = DNS_SSUMATCHTYPE_SUBDOMAIN; + else if (strcasecmp(str, "wildcard") == 0) + mtype = DNS_SSUMATCHTYPE_WILDCARD; + else if (strcasecmp(str, "self") == 0) + mtype = DNS_SSUMATCHTYPE_SELF; + else if (strcasecmp(str, "selfsub") == 0) + mtype = DNS_SSUMATCHTYPE_SELFSUB; + else if (strcasecmp(str, "selfwild") == 0) + mtype = DNS_SSUMATCHTYPE_SELFWILD; + else if (strcasecmp(str, "ms-self") == 0) + mtype = DNS_SSUMATCHTYPE_SELFMS; + else if (strcasecmp(str, "krb5-self") == 0) + mtype = DNS_SSUMATCHTYPE_SELFKRB5; + else if (strcasecmp(str, "ms-subdomain") == 0) + mtype = DNS_SSUMATCHTYPE_SUBDOMAINMS; + else if (strcasecmp(str, "krb5-subdomain") == 0) + mtype = DNS_SSUMATCHTYPE_SUBDOMAINKRB5; + else + INSIST(0); + + dns_fixedname_init(&fident); + str = cfg_obj_asstring(identity); + isc_buffer_init(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + result = dns_name_fromtext(dns_fixedname_name(&fident), &b, + dns_rootname, ISC_FALSE, NULL); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR, + "'%s' is not a valid name", str); + goto cleanup; + } + + dns_fixedname_init(&fname); + str = cfg_obj_asstring(dname); + isc_buffer_init(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + result = dns_name_fromtext(dns_fixedname_name(&fname), &b, + dns_rootname, ISC_FALSE, NULL); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR, + "'%s' is not a valid name", str); + goto cleanup; + } + + n = ns_config_listcount(typelist); + if (n == 0) + types = NULL; + else { + types = isc_mem_get(mctx, n * sizeof(dns_rdatatype_t)); + if (types == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup; + } + } + + i = 0; + for (element2 = cfg_list_first(typelist); + element2 != NULL; + element2 = cfg_list_next(element2)) + { + const cfg_obj_t *typeobj; + isc_textregion_t r; + + INSIST(i < n); + + typeobj = cfg_listelt_value(element2); + str = cfg_obj_asstring(typeobj); + DE_CONST(str, r.base); + r.length = strlen(str); + + result = dns_rdatatype_fromtext(&types[i++], &r); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR, + "'%s' is not a valid type", str); + isc_mem_put(mctx, types, + n * sizeof(dns_rdatatype_t)); + goto cleanup; + } + } + INSIST(i == n); + + result = dns_ssutable_addrule(table, grant, + dns_fixedname_name(&fident), + mtype, + dns_fixedname_name(&fname), + n, types); + if (types != NULL) + isc_mem_put(mctx, types, n * sizeof(dns_rdatatype_t)); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + } + + result = ISC_R_SUCCESS; + dns_zone_setssutable(zone, table); + + cleanup: + dns_ssutable_detach(&table); + return (result); +} + +/*% + * Convert a config file zone type into a server zone type. + */ +static inline dns_zonetype_t +zonetype_fromconfig(const cfg_obj_t *map) { + const cfg_obj_t *obj = NULL; + isc_result_t result; + + result = cfg_map_get(map, "type", &obj); + INSIST(result == ISC_R_SUCCESS); + return (ns_config_getzonetype(obj)); +} + +/*% + * Helper function for strtoargv(). Pardon the gratuitous recursion. + */ +static isc_result_t +strtoargvsub(isc_mem_t *mctx, char *s, unsigned int *argcp, + char ***argvp, unsigned int n) +{ + isc_result_t result; + + /* Discard leading whitespace. */ + while (*s == ' ' || *s == '\t') + s++; + + if (*s == '\0') { + /* We have reached the end of the string. */ + *argcp = n; + *argvp = isc_mem_get(mctx, n * sizeof(char *)); + if (*argvp == NULL) + return (ISC_R_NOMEMORY); + } else { + char *p = s; + while (*p != ' ' && *p != '\t' && *p != '\0') + p++; + if (*p != '\0') + *p++ = '\0'; + + result = strtoargvsub(mctx, p, argcp, argvp, n + 1); + if (result != ISC_R_SUCCESS) + return (result); + (*argvp)[n] = s; + } + return (ISC_R_SUCCESS); +} + +/*% + * Tokenize the string "s" into whitespace-separated words, + * return the number of words in '*argcp' and an array + * of pointers to the words in '*argvp'. The caller + * must free the array using isc_mem_put(). The string + * is modified in-place. + */ +static isc_result_t +strtoargv(isc_mem_t *mctx, char *s, unsigned int *argcp, char ***argvp) { + return (strtoargvsub(mctx, s, argcp, argvp, 0)); +} + +static void +checknames(dns_zonetype_t ztype, const cfg_obj_t **maps, + const cfg_obj_t **objp) +{ + const char *zone = NULL; + isc_result_t result; + + switch (ztype) { + case dns_zone_slave: zone = "slave"; break; + case dns_zone_master: zone = "master"; break; + default: + INSIST(0); + } + result = ns_checknames_get(maps, zone, objp); + INSIST(result == ISC_R_SUCCESS); +} + +isc_result_t +ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, + const cfg_obj_t *zconfig, cfg_aclconfctx_t *ac, + dns_zone_t *zone) +{ + isc_result_t result; + const char *zname; + dns_rdataclass_t zclass; + dns_rdataclass_t vclass; + const cfg_obj_t *maps[5]; + const cfg_obj_t *zoptions = NULL; + const cfg_obj_t *options = NULL; + const cfg_obj_t *obj; + const char *filename = NULL; + dns_notifytype_t notifytype = dns_notifytype_yes; + isc_sockaddr_t *addrs; + dns_name_t **keynames; + isc_uint32_t count; + char *cpval; + unsigned int dbargc; + char **dbargv; + static char default_dbtype[] = "rbt"; + isc_mem_t *mctx = dns_zone_getmctx(zone); + dns_dialuptype_t dialup = dns_dialuptype_no; + dns_zonetype_t ztype; + int i; + isc_int32_t journal_size; + isc_boolean_t multi; + isc_boolean_t alt; + dns_view_t *view; + isc_boolean_t check = ISC_FALSE, fail = ISC_FALSE; + isc_boolean_t warn = ISC_FALSE, ignore = ISC_FALSE; + isc_boolean_t ixfrdiff; + dns_masterformat_t masterformat; + isc_stats_t *zoneqrystats; + isc_boolean_t zonestats_on; + + i = 0; + if (zconfig != NULL) { + zoptions = cfg_tuple_get(zconfig, "options"); + maps[i++] = zoptions; + } + if (vconfig != NULL) + maps[i++] = cfg_tuple_get(vconfig, "options"); + if (config != NULL) { + (void)cfg_map_get(config, "options", &options); + if (options != NULL) + maps[i++] = options; + } + maps[i++] = ns_g_defaults; + maps[i++] = NULL; + + if (vconfig != NULL) + RETERR(ns_config_getclass(cfg_tuple_get(vconfig, "class"), + dns_rdataclass_in, &vclass)); + else + vclass = dns_rdataclass_in; + + /* + * Configure values common to all zone types. + */ + + zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); + + RETERR(ns_config_getclass(cfg_tuple_get(zconfig, "class"), + vclass, &zclass)); + dns_zone_setclass(zone, zclass); + + ztype = zonetype_fromconfig(zoptions); + dns_zone_settype(zone, ztype); + + obj = NULL; + result = cfg_map_get(zoptions, "database", &obj); + if (result == ISC_R_SUCCESS) + cpval = isc_mem_strdup(mctx, cfg_obj_asstring(obj)); + else + cpval = default_dbtype; + + if (cpval == NULL) + return(ISC_R_NOMEMORY); + + result = strtoargv(mctx, cpval, &dbargc, &dbargv); + if (result != ISC_R_SUCCESS && cpval != default_dbtype) { + isc_mem_free(mctx, cpval); + return (result); + } + + /* + * ANSI C is strange here. There is no logical reason why (char **) + * cannot be promoted automatically to (const char * const *) by the + * compiler w/o generating a warning. + */ + result = dns_zone_setdbtype(zone, dbargc, (const char * const *)dbargv); + isc_mem_put(mctx, dbargv, dbargc * sizeof(*dbargv)); + if (cpval != default_dbtype) + isc_mem_free(mctx, cpval); + if (result != ISC_R_SUCCESS) + return (result); + + obj = NULL; + result = cfg_map_get(zoptions, "file", &obj); + if (result == ISC_R_SUCCESS) + filename = cfg_obj_asstring(obj); + + masterformat = dns_masterformat_text; + obj = NULL; + result= ns_config_get(maps, "masterfile-format", &obj); + if (result == ISC_R_SUCCESS) { + const char *masterformatstr = cfg_obj_asstring(obj); + + if (strcasecmp(masterformatstr, "text") == 0) + masterformat = dns_masterformat_text; + else if (strcasecmp(masterformatstr, "raw") == 0) + masterformat = dns_masterformat_raw; + else + INSIST(0); + } + RETERR(dns_zone_setfile2(zone, filename, masterformat)); + + obj = NULL; + result = cfg_map_get(zoptions, "journal", &obj); + if (result == ISC_R_SUCCESS) + RETERR(dns_zone_setjournal(zone, cfg_obj_asstring(obj))); + + if (ztype == dns_zone_slave) + RETERR(configure_zone_acl(zconfig, vconfig, config, + allow_notify, ac, zone, + dns_zone_setnotifyacl, + dns_zone_clearnotifyacl)); + /* + * XXXAG This probably does not make sense for stubs. + */ + RETERR(configure_zone_acl(zconfig, vconfig, config, + allow_query, ac, zone, + dns_zone_setqueryacl, + dns_zone_clearqueryacl)); + + obj = NULL; + result = ns_config_get(maps, "dialup", &obj); + INSIST(result == ISC_R_SUCCESS); + if (cfg_obj_isboolean(obj)) { + if (cfg_obj_asboolean(obj)) + dialup = dns_dialuptype_yes; + else + dialup = dns_dialuptype_no; + } else { + const char *dialupstr = cfg_obj_asstring(obj); + if (strcasecmp(dialupstr, "notify") == 0) + dialup = dns_dialuptype_notify; + else if (strcasecmp(dialupstr, "notify-passive") == 0) + dialup = dns_dialuptype_notifypassive; + else if (strcasecmp(dialupstr, "refresh") == 0) + dialup = dns_dialuptype_refresh; + else if (strcasecmp(dialupstr, "passive") == 0) + dialup = dns_dialuptype_passive; + else + INSIST(0); + } + dns_zone_setdialup(zone, dialup); + + obj = NULL; + result = ns_config_get(maps, "zone-statistics", &obj); + INSIST(result == ISC_R_SUCCESS); + zonestats_on = cfg_obj_asboolean(obj); + zoneqrystats = NULL; + if (zonestats_on) { + RETERR(isc_stats_create(mctx, &zoneqrystats, + dns_nsstatscounter_max)); + } + dns_zone_setrequeststats(zone, zoneqrystats); + if (zoneqrystats != NULL) + isc_stats_detach(&zoneqrystats); + + /* + * Configure master functionality. This applies + * to primary masters (type "master") and slaves + * acting as masters (type "slave"), but not to stubs. + */ + if (ztype != dns_zone_stub) { + obj = NULL; + result = ns_config_get(maps, "notify", &obj); + INSIST(result == ISC_R_SUCCESS); + if (cfg_obj_isboolean(obj)) { + if (cfg_obj_asboolean(obj)) + notifytype = dns_notifytype_yes; + else + notifytype = dns_notifytype_no; + } else { + const char *notifystr = cfg_obj_asstring(obj); + if (strcasecmp(notifystr, "explicit") == 0) + notifytype = dns_notifytype_explicit; + else if (strcasecmp(notifystr, "master-only") == 0) + notifytype = dns_notifytype_masteronly; + else + INSIST(0); + } + dns_zone_setnotifytype(zone, notifytype); + + obj = NULL; + result = ns_config_get(maps, "also-notify", &obj); + if (result == ISC_R_SUCCESS) { + isc_sockaddr_t *addrs = NULL; + isc_uint32_t addrcount; + result = ns_config_getiplist(config, obj, 0, mctx, + &addrs, &addrcount); + if (result != ISC_R_SUCCESS) + return (result); + result = dns_zone_setalsonotify(zone, addrs, + addrcount); + ns_config_putiplist(mctx, &addrs, addrcount); + if (result != ISC_R_SUCCESS) + return (result); + } else + RETERR(dns_zone_setalsonotify(zone, NULL, 0)); + + obj = NULL; + result = ns_config_get(maps, "notify-source", &obj); + INSIST(result == ISC_R_SUCCESS); + RETERR(dns_zone_setnotifysrc4(zone, cfg_obj_assockaddr(obj))); + ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); + + obj = NULL; + result = ns_config_get(maps, "notify-source-v6", &obj); + INSIST(result == ISC_R_SUCCESS); + RETERR(dns_zone_setnotifysrc6(zone, cfg_obj_assockaddr(obj))); + ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); + + obj = NULL; + result = ns_config_get(maps, "notify-to-soa", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zone_setoption(zone, DNS_ZONEOPT_NOTIFYTOSOA, + cfg_obj_asboolean(obj)); + + dns_zone_setisself(zone, ns_client_isself, NULL); + + RETERR(configure_zone_acl(zconfig, vconfig, config, + allow_transfer, ac, zone, + dns_zone_setxfracl, + dns_zone_clearxfracl)); + + obj = NULL; + result = ns_config_get(maps, "max-transfer-time-out", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zone_setmaxxfrout(zone, cfg_obj_asuint32(obj) * 60); + + obj = NULL; + result = ns_config_get(maps, "max-transfer-idle-out", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zone_setidleout(zone, cfg_obj_asuint32(obj) * 60); + + obj = NULL; + result = ns_config_get(maps, "max-journal-size", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zone_setjournalsize(zone, -1); + if (cfg_obj_isstring(obj)) { + const char *str = cfg_obj_asstring(obj); + INSIST(strcasecmp(str, "unlimited") == 0); + journal_size = ISC_UINT32_MAX / 2; + } else { + isc_resourcevalue_t value; + value = cfg_obj_asuint64(obj); + if (value > ISC_UINT32_MAX / 2) { + cfg_obj_log(obj, ns_g_lctx, + ISC_LOG_ERROR, + "'max-journal-size " + "%" ISC_PRINT_QUADFORMAT "d' " + "is too large", + value); + RETERR(ISC_R_RANGE); + } + journal_size = (isc_uint32_t)value; + } + dns_zone_setjournalsize(zone, journal_size); + + obj = NULL; + result = ns_config_get(maps, "ixfr-from-differences", &obj); + INSIST(result == ISC_R_SUCCESS); + if (cfg_obj_isboolean(obj)) + ixfrdiff = cfg_obj_asboolean(obj); + else if (strcasecmp(cfg_obj_asstring(obj), "master") && + ztype == dns_zone_master) + ixfrdiff = ISC_TRUE; + else if (strcasecmp(cfg_obj_asstring(obj), "slave") && + ztype == dns_zone_slave) + ixfrdiff = ISC_TRUE; + else + ixfrdiff = ISC_FALSE; + dns_zone_setoption(zone, DNS_ZONEOPT_IXFRFROMDIFFS, ixfrdiff); + + checknames(ztype, maps, &obj); + INSIST(obj != NULL); + if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { + fail = ISC_FALSE; + check = ISC_TRUE; + } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { + fail = check = ISC_TRUE; + } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { + fail = check = ISC_FALSE; + } else + INSIST(0); + dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMES, check); + dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMESFAIL, fail); + + obj = NULL; + result = ns_config_get(maps, "notify-delay", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zone_setnotifydelay(zone, cfg_obj_asuint32(obj)); + + obj = NULL; + result = ns_config_get(maps, "check-sibling", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zone_setoption(zone, DNS_ZONEOPT_CHECKSIBLING, + cfg_obj_asboolean(obj)); + + obj = NULL; + result = ns_config_get(maps, "zero-no-soa-ttl", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zone_setzeronosoattl(zone, cfg_obj_asboolean(obj)); + } + + /* + * Configure update-related options. These apply to + * primary masters only. + */ + if (ztype == dns_zone_master) { + dns_acl_t *updateacl; + RETERR(configure_zone_acl(zconfig, vconfig, config, + allow_update, ac, zone, + dns_zone_setupdateacl, + dns_zone_clearupdateacl)); + + updateacl = dns_zone_getupdateacl(zone); + if (updateacl != NULL && dns_acl_isinsecure(updateacl)) + isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_SERVER, ISC_LOG_WARNING, + "zone '%s' allows updates by IP " + "address, which is insecure", + zname); + + RETERR(configure_zone_ssutable(zoptions, zone)); + + obj = NULL; + result = ns_config_get(maps, "sig-validity-interval", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zone_setsigvalidityinterval(zone, + cfg_obj_asuint32(obj) * 86400); + + obj = NULL; + result = ns_config_get(maps, "key-directory", &obj); + if (result == ISC_R_SUCCESS) { + filename = cfg_obj_asstring(obj); + if (!isc_file_isabsolute(filename)) { + cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, + "key-directory '%s' " + "is not absolute", filename); + return (ISC_R_FAILURE); + } + RETERR(dns_zone_setkeydirectory(zone, filename)); + } + + obj = NULL; + result = ns_config_get(maps, "check-wildcard", &obj); + if (result == ISC_R_SUCCESS) + check = cfg_obj_asboolean(obj); + else + check = ISC_FALSE; + dns_zone_setoption(zone, DNS_ZONEOPT_CHECKWILDCARD, check); + + obj = NULL; + result = ns_config_get(maps, "check-mx", &obj); + INSIST(obj != NULL); + if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { + fail = ISC_FALSE; + check = ISC_TRUE; + } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { + fail = check = ISC_TRUE; + } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { + fail = check = ISC_FALSE; + } else + INSIST(0); + dns_zone_setoption(zone, DNS_ZONEOPT_CHECKMX, check); + dns_zone_setoption(zone, DNS_ZONEOPT_CHECKMXFAIL, fail); + + obj = NULL; + result = ns_config_get(maps, "check-integrity", &obj); + INSIST(obj != NULL); + dns_zone_setoption(zone, DNS_ZONEOPT_CHECKINTEGRITY, + cfg_obj_asboolean(obj)); + + obj = NULL; + result = ns_config_get(maps, "check-mx-cname", &obj); + INSIST(obj != NULL); + if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { + warn = ISC_TRUE; + ignore = ISC_FALSE; + } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { + warn = ignore = ISC_FALSE; + } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { + warn = ignore = ISC_TRUE; + } else + INSIST(0); + dns_zone_setoption(zone, DNS_ZONEOPT_WARNMXCNAME, warn); + dns_zone_setoption(zone, DNS_ZONEOPT_IGNOREMXCNAME, ignore); + + obj = NULL; + result = ns_config_get(maps, "check-srv-cname", &obj); + INSIST(obj != NULL); + if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { + warn = ISC_TRUE; + ignore = ISC_FALSE; + } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { + warn = ignore = ISC_FALSE; + } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { + warn = ignore = ISC_TRUE; + } else + INSIST(0); + dns_zone_setoption(zone, DNS_ZONEOPT_WARNSRVCNAME, warn); + dns_zone_setoption(zone, DNS_ZONEOPT_IGNORESRVCNAME, ignore); + + obj = NULL; + result = ns_config_get(maps, "update-check-ksk", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zone_setoption(zone, DNS_ZONEOPT_UPDATECHECKKSK, + cfg_obj_asboolean(obj)); + } else if (ztype == dns_zone_slave) { + RETERR(configure_zone_acl(zconfig, vconfig, config, + allow_update_forwarding, ac, zone, + dns_zone_setforwardacl, + dns_zone_clearforwardacl)); + } + + /* + * Configure slave functionality. + */ + switch (ztype) { + case dns_zone_slave: + case dns_zone_stub: + count = 0; + obj = NULL; + result = cfg_map_get(zoptions, "masters", &obj); + if (obj != NULL) { + addrs = NULL; + keynames = NULL; + RETERR(ns_config_getipandkeylist(config, obj, mctx, + &addrs, &keynames, + &count)); + result = dns_zone_setmasterswithkeys(zone, addrs, + keynames, count); + ns_config_putipandkeylist(mctx, &addrs, &keynames, + count); + } else + result = dns_zone_setmasters(zone, NULL, 0); + RETERR(result); + + multi = ISC_FALSE; + if (count > 1) { + obj = NULL; + result = ns_config_get(maps, "multi-master", &obj); + INSIST(result == ISC_R_SUCCESS); + multi = cfg_obj_asboolean(obj); + } + dns_zone_setoption(zone, DNS_ZONEOPT_MULTIMASTER, multi); + + obj = NULL; + result = ns_config_get(maps, "max-transfer-time-in", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zone_setmaxxfrin(zone, cfg_obj_asuint32(obj) * 60); + + obj = NULL; + result = ns_config_get(maps, "max-transfer-idle-in", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zone_setidlein(zone, cfg_obj_asuint32(obj) * 60); + + obj = NULL; + result = ns_config_get(maps, "max-refresh-time", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zone_setmaxrefreshtime(zone, cfg_obj_asuint32(obj)); + + obj = NULL; + result = ns_config_get(maps, "min-refresh-time", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zone_setminrefreshtime(zone, cfg_obj_asuint32(obj)); + + obj = NULL; + result = ns_config_get(maps, "max-retry-time", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zone_setmaxretrytime(zone, cfg_obj_asuint32(obj)); + + obj = NULL; + result = ns_config_get(maps, "min-retry-time", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zone_setminretrytime(zone, cfg_obj_asuint32(obj)); + + obj = NULL; + result = ns_config_get(maps, "transfer-source", &obj); + INSIST(result == ISC_R_SUCCESS); + RETERR(dns_zone_setxfrsource4(zone, cfg_obj_assockaddr(obj))); + ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); + + obj = NULL; + result = ns_config_get(maps, "transfer-source-v6", &obj); + INSIST(result == ISC_R_SUCCESS); + RETERR(dns_zone_setxfrsource6(zone, cfg_obj_assockaddr(obj))); + ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); + + obj = NULL; + result = ns_config_get(maps, "alt-transfer-source", &obj); + INSIST(result == ISC_R_SUCCESS); + RETERR(dns_zone_setaltxfrsource4(zone, cfg_obj_assockaddr(obj))); + + obj = NULL; + result = ns_config_get(maps, "alt-transfer-source-v6", &obj); + INSIST(result == ISC_R_SUCCESS); + RETERR(dns_zone_setaltxfrsource6(zone, cfg_obj_assockaddr(obj))); + + obj = NULL; + (void)ns_config_get(maps, "use-alt-transfer-source", &obj); + if (obj == NULL) { + /* + * Default off when views are in use otherwise + * on for BIND 8 compatibility. + */ + view = dns_zone_getview(zone); + if (view != NULL && strcmp(view->name, "_default") == 0) + alt = ISC_TRUE; + else + alt = ISC_FALSE; + } else + alt = cfg_obj_asboolean(obj); + dns_zone_setoption(zone, DNS_ZONEOPT_USEALTXFRSRC, alt); + + obj = NULL; + (void)ns_config_get(maps, "try-tcp-refresh", &obj); + dns_zone_setoption(zone, DNS_ZONEOPT_TRYTCPREFRESH, + cfg_obj_asboolean(obj)); + break; + + default: + break; + } + + return (ISC_R_SUCCESS); +} + +isc_boolean_t +ns_zone_reusable(dns_zone_t *zone, const cfg_obj_t *zconfig) { + const cfg_obj_t *zoptions = NULL; + const cfg_obj_t *obj = NULL; + const char *cfilename; + const char *zfilename; + + zoptions = cfg_tuple_get(zconfig, "options"); + + if (zonetype_fromconfig(zoptions) != dns_zone_gettype(zone)) + return (ISC_FALSE); + + obj = NULL; + (void)cfg_map_get(zoptions, "file", &obj); + if (obj != NULL) + cfilename = cfg_obj_asstring(obj); + else + cfilename = NULL; + zfilename = dns_zone_getfile(zone); + if (!((cfilename == NULL && zfilename == NULL) || + (cfilename != NULL && zfilename != NULL && + strcmp(cfilename, zfilename) == 0))) + return (ISC_FALSE); + + return (ISC_TRUE); +} diff --git a/contrib/bind-9.5.2/bin/nsupdate/nsupdate.1 b/contrib/bind-9.5.2/bin/nsupdate/nsupdate.1 new file mode 100644 index 0000000000..8425be522f --- /dev/null +++ b/contrib/bind-9.5.2/bin/nsupdate/nsupdate.1 @@ -0,0 +1,358 @@ +.\" 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 +.\" 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: nsupdate.1,v 1.1.2.4 2009/07/11 01:43:29 tbox Exp $ +.\" +.hy 0 +.ad l +.\" Title: nsupdate +.\" Author: +.\" Generator: DocBook XSL Stylesheets v1.71.1 +.\" Date: Jun 30, 2000 +.\" Manual: BIND9 +.\" Source: BIND9 +.\" +.TH "NSUPDATE" "1" "Jun 30, 2000" "BIND9" "BIND9" +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.SH "NAME" +nsupdate \- Dynamic DNS update utility +.SH "SYNOPSIS" +.HP 9 +\fBnsupdate\fR [\fB\-d\fR] [[\fB\-y\ \fR\fB\fI[hmac:]\fR\fIkeyname:secret\fR\fR] | [\fB\-k\ \fR\fB\fIkeyfile\fR\fR]] [\fB\-t\ \fR\fB\fItimeout\fR\fR] [\fB\-u\ \fR\fB\fIudptimeout\fR\fR] [\fB\-r\ \fR\fB\fIudpretries\fR\fR] [\fB\-R\ \fR\fB\fIrandomdev\fR\fR] [\fB\-v\fR] [filename] +.SH "DESCRIPTION" +.PP +\fBnsupdate\fR +is used to submit Dynamic DNS Update requests as defined in RFC2136 to a name server. This allows resource records to be added or removed from a zone without manually editing the zone file. A single update request can contain requests to add or remove more than one resource record. +.PP +Zones that are under dynamic control via +\fBnsupdate\fR +or a DHCP server should not be edited by hand. Manual edits could conflict with dynamic updates and cause data to be lost. +.PP +The resource records that are dynamically added or removed with +\fBnsupdate\fR +have to be in the same zone. Requests are sent to the zone's master server. This is identified by the MNAME field of the zone's SOA record. +.PP +The +\fB\-d\fR +option makes +\fBnsupdate\fR +operate in debug mode. This provides tracing information about the update requests that are made and the replies received from the name server. +.PP +Transaction signatures can be used to authenticate the Dynamic DNS updates. These use the TSIG resource record type described in RFC2845 or the SIG(0) record described in RFC3535 and RFC2931. TSIG relies on a shared secret that should only be known to +\fBnsupdate\fR +and the name server. Currently, the only supported encryption algorithm for TSIG is HMAC\-MD5, which is defined in RFC 2104. Once other algorithms are defined for TSIG, applications will need to ensure they select the appropriate algorithm as well as the key when authenticating each other. For instance, suitable +\fBkey\fR +and +\fBserver\fR +statements would be added to +\fI/etc/named.conf\fR +so that the name server can associate the appropriate secret key and algorithm with the IP address of the client application that will be using TSIG authentication. SIG(0) uses public key cryptography. To use a SIG(0) key, the public key must be stored in a KEY record in a zone served by the name server. +\fBnsupdate\fR +does not read +\fI/etc/named.conf\fR. +.PP +\fBnsupdate\fR +uses the +\fB\-y\fR +or +\fB\-k\fR +option to provide the shared secret needed to generate a TSIG record for authenticating Dynamic DNS update requests, default type HMAC\-MD5. These options are mutually exclusive. With the +\fB\-k\fR +option, +\fBnsupdate\fR +reads the shared secret from the file +\fIkeyfile\fR, whose name is of the form +\fIK{name}.+157.+{random}.private\fR. For historical reasons, the file +\fIK{name}.+157.+{random}.key\fR +must also be present. When the +\fB\-y\fR +option is used, a signature is generated from +[\fIhmac:\fR]\fIkeyname:secret.\fR +\fIkeyname\fR +is the name of the key, and +\fIsecret\fR +is the base64 encoded shared secret. Use of the +\fB\-y\fR +option is discouraged because the shared secret is supplied as a command line argument in clear text. This may be visible in the output from +\fBps\fR(1) +or in a history file maintained by the user's shell. +.PP +The +\fB\-k\fR +may also be used to specify a SIG(0) key used to authenticate Dynamic DNS update requests. In this case, the key specified is not an HMAC\-MD5 key. +.PP +By default, +\fBnsupdate\fR +uses UDP to send update requests to the name server unless they are too large to fit in a UDP request in which case TCP will be used. The +\fB\-v\fR +option makes +\fBnsupdate\fR +use a TCP connection. This may be preferable when a batch of update requests is made. +.PP +The +\fB\-t\fR +option sets the maximum time an update request can take before it is aborted. The default is 300 seconds. Zero can be used to disable the timeout. +.PP +The +\fB\-u\fR +option sets the UDP retry interval. The default is 3 seconds. If zero, the interval will be computed from the timeout interval and number of UDP retries. +.PP +The +\fB\-r\fR +option sets the number of UDP retries. The default is 3. If zero, only one update request will be made. +.PP +The +\fB\-R \fR\fB\fIrandomdev\fR\fR +option specifies a source of randomness. If the operating system does not provide a +\fI/dev/random\fR +or equivalent device, the default source of randomness is keyboard input. +\fIrandomdev\fR +specifies the name of a character device or file containing random data to be used instead of the default. The special value +\fIkeyboard\fR +indicates that keyboard input should be used. This option may be specified multiple times. +.SH "INPUT FORMAT" +.PP +\fBnsupdate\fR +reads input from +\fIfilename\fR +or standard input. Each command is supplied on exactly one line of input. Some commands are for administrative purposes. The others are either update instructions or prerequisite checks on the contents of the zone. These checks set conditions that some name or set of resource records (RRset) either exists or is absent from the zone. These conditions must be met if the entire update request is to succeed. Updates will be rejected if the tests for the prerequisite conditions fail. +.PP +Every update request consists of zero or more prerequisites and zero or more updates. This allows a suitably authenticated update request to proceed if some specified resource records are present or missing from the zone. A blank input line (or the +\fBsend\fR +command) causes the accumulated commands to be sent as one Dynamic DNS update request to the name server. +.PP +The command formats and their meaning are as follows: +.PP +\fBserver\fR {servername} [port] +.RS 4 +Sends all dynamic update requests to the name server +\fIservername\fR. When no server statement is provided, +\fBnsupdate\fR +will send updates to the master server of the correct zone. The MNAME field of that zone's SOA record will identify the master server for that zone. +\fIport\fR +is the port number on +\fIservername\fR +where the dynamic update requests get sent. If no port number is specified, the default DNS port number of 53 is used. +.RE +.PP +\fBlocal\fR {address} [port] +.RS 4 +Sends all dynamic update requests using the local +\fIaddress\fR. When no local statement is provided, +\fBnsupdate\fR +will send updates using an address and port chosen by the system. +\fIport\fR +can additionally be used to make requests come from a specific port. If no port number is specified, the system will assign one. +.RE +.PP +\fBzone\fR {zonename} +.RS 4 +Specifies that all updates are to be made to the zone +\fIzonename\fR. If no +\fIzone\fR +statement is provided, +\fBnsupdate\fR +will attempt determine the correct zone to update based on the rest of the input. +.RE +.PP +\fBclass\fR {classname} +.RS 4 +Specify the default class. If no +\fIclass\fR +is specified, the default class is +\fIIN\fR. +.RE +.PP +\fBkey\fR {name} {secret} +.RS 4 +Specifies that all updates are to be TSIG\-signed using the +\fIkeyname\fR +\fIkeysecret\fR +pair. The +\fBkey\fR +command overrides any key specified on the command line via +\fB\-y\fR +or +\fB\-k\fR. +.RE +.PP +\fBprereq nxdomain\fR {domain\-name} +.RS 4 +Requires that no resource record of any type exists with name +\fIdomain\-name\fR. +.RE +.PP +\fBprereq yxdomain\fR {domain\-name} +.RS 4 +Requires that +\fIdomain\-name\fR +exists (has as at least one resource record, of any type). +.RE +.PP +\fBprereq nxrrset\fR {domain\-name} [class] {type} +.RS 4 +Requires that no resource record exists of the specified +\fItype\fR, +\fIclass\fR +and +\fIdomain\-name\fR. If +\fIclass\fR +is omitted, IN (internet) is assumed. +.RE +.PP +\fBprereq yxrrset\fR {domain\-name} [class] {type} +.RS 4 +This requires that a resource record of the specified +\fItype\fR, +\fIclass\fR +and +\fIdomain\-name\fR +must exist. If +\fIclass\fR +is omitted, IN (internet) is assumed. +.RE +.PP +\fBprereq yxrrset\fR {domain\-name} [class] {type} {data...} +.RS 4 +The +\fIdata\fR +from each set of prerequisites of this form sharing a common +\fItype\fR, +\fIclass\fR, and +\fIdomain\-name\fR +are combined to form a set of RRs. This set of RRs must exactly match the set of RRs existing in the zone at the given +\fItype\fR, +\fIclass\fR, and +\fIdomain\-name\fR. The +\fIdata\fR +are written in the standard text representation of the resource record's RDATA. +.RE +.PP +\fBupdate delete\fR {domain\-name} [ttl] [class] [type\ [data...]] +.RS 4 +Deletes any resource records named +\fIdomain\-name\fR. If +\fItype\fR +and +\fIdata\fR +is provided, only matching resource records will be removed. The internet class is assumed if +\fIclass\fR +is not supplied. The +\fIttl\fR +is ignored, and is only allowed for compatibility. +.RE +.PP +\fBupdate add\fR {domain\-name} {ttl} [class] {type} {data...} +.RS 4 +Adds a new resource record with the specified +\fIttl\fR, +\fIclass\fR +and +\fIdata\fR. +.RE +.PP +\fBshow\fR +.RS 4 +Displays the current message, containing all of the prerequisites and updates specified since the last send. +.RE +.PP +\fBsend\fR +.RS 4 +Sends the current message. This is equivalent to entering a blank line. +.RE +.PP +\fBanswer\fR +.RS 4 +Displays the answer. +.RE +.PP +Lines beginning with a semicolon are comments and are ignored. +.SH "EXAMPLES" +.PP +The examples below show how +\fBnsupdate\fR +could be used to insert and delete resource records from the +\fBexample.com\fR +zone. Notice that the input in each example contains a trailing blank line so that a group of commands are sent as one dynamic update request to the master name server for +\fBexample.com\fR. +.sp +.RS 4 +.nf +# nsupdate +> update delete oldhost.example.com A +> update add newhost.example.com 86400 A 172.16.1.1 +> send +.fi +.RE +.sp +.PP +Any A records for +\fBoldhost.example.com\fR +are deleted. And an A record for +\fBnewhost.example.com\fR +with IP address 172.16.1.1 is added. The newly\-added record has a 1 day TTL (86400 seconds). +.sp +.RS 4 +.nf +# nsupdate +> prereq nxdomain nickname.example.com +> update add nickname.example.com 86400 CNAME somehost.example.com +> send +.fi +.RE +.sp +.PP +The prerequisite condition gets the name server to check that there are no resource records of any type for +\fBnickname.example.com\fR. If there are, the update request fails. If this name does not exist, a CNAME for it is added. This ensures that when the CNAME is added, it cannot conflict with the long\-standing rule in RFC1034 that a name must not exist as any other record type if it exists as a CNAME. (The rule has been updated for DNSSEC in RFC2535 to allow CNAMEs to have RRSIG, DNSKEY and NSEC records.) +.SH "FILES" +.PP +\fB/etc/resolv.conf\fR +.RS 4 +used to identify default name server +.RE +.PP +\fBK{name}.+157.+{random}.key\fR +.RS 4 +base\-64 encoding of HMAC\-MD5 key created by +\fBdnssec\-keygen\fR(8). +.RE +.PP +\fBK{name}.+157.+{random}.private\fR +.RS 4 +base\-64 encoding of HMAC\-MD5 key created by +\fBdnssec\-keygen\fR(8). +.RE +.SH "SEE ALSO" +.PP +\fBRFC2136\fR(), +\fBRFC3007\fR(), +\fBRFC2104\fR(), +\fBRFC2845\fR(), +\fBRFC1034\fR(), +\fBRFC2535\fR(), +\fBRFC2931\fR(), +\fBnamed\fR(8), +\fBdnssec\-keygen\fR(8). +.SH "BUGS" +.PP +The TSIG key is redundantly stored in two separate files. This is a consequence of nsupdate using the DST library for its cryptographic operations, and may change in future releases. +.SH "COPYRIGHT" +Copyright \(co 2004\-2009 Internet Systems Consortium, Inc. ("ISC") +.br +Copyright \(co 2000\-2003 Internet Software Consortium. +.br diff --git a/contrib/bind-9.5.2/bin/nsupdate/nsupdate.c b/contrib/bind-9.5.2/bin/nsupdate/nsupdate.c new file mode 100644 index 0000000000..c641f53806 --- /dev/null +++ b/contrib/bind-9.5.2/bin/nsupdate/nsupdate.c @@ -0,0 +1,2682 @@ +/* + * 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 + * 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: nsupdate.c,v 1.154.56.6 2009/04/30 07:12:15 marka Exp $ */ + +/*! \file */ + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#ifdef GSSAPI +#include +#endif +#include + + +#ifdef HAVE_ADDRINFO +#ifdef HAVE_GETADDRINFO +#ifdef HAVE_GAISTRERROR +#define USE_GETADDRINFO +#endif +#endif +#endif + +#ifndef USE_GETADDRINFO +#ifndef ISC_PLATFORM_NONSTDHERRNO +extern int h_errno; +#endif +#endif + +#define MAXCMD (4 * 1024) +#define MAXWIRE (64 * 1024) +#define PACKETSIZE ((64 * 1024) - 1) +#define INITTEXT (2 * 1024) +#define MAXTEXT (128 * 1024) +#define FIND_TIMEOUT 5 +#define TTL_MAX 2147483647U /* Maximum signed 32 bit integer. */ + +#define DNSDEFAULTPORT 53 + +#ifndef RESOLV_CONF +#define RESOLV_CONF "/etc/resolv.conf" +#endif + +static isc_boolean_t debugging = ISC_FALSE, ddebugging = ISC_FALSE; +static isc_boolean_t memdebugging = ISC_FALSE; +static isc_boolean_t have_ipv4 = ISC_FALSE; +static isc_boolean_t have_ipv6 = ISC_FALSE; +static isc_boolean_t is_dst_up = ISC_FALSE; +static isc_boolean_t usevc = ISC_FALSE; +static isc_boolean_t usegsstsig = ISC_FALSE; +static isc_boolean_t use_win2k_gsstsig = ISC_FALSE; +static isc_boolean_t tried_other_gsstsig = ISC_FALSE; +static isc_taskmgr_t *taskmgr = NULL; +static isc_task_t *global_task = NULL; +static isc_event_t *global_event = NULL; +static isc_log_t *lctx = NULL; +static isc_mem_t *mctx = NULL; +static dns_dispatchmgr_t *dispatchmgr = NULL; +static dns_requestmgr_t *requestmgr = NULL; +static isc_socketmgr_t *socketmgr = NULL; +static isc_timermgr_t *timermgr = NULL; +static dns_dispatch_t *dispatchv4 = NULL; +static dns_dispatch_t *dispatchv6 = NULL; +static dns_message_t *updatemsg = NULL; +static dns_fixedname_t fuserzone; +static dns_name_t *userzone = NULL; +static dns_name_t *zonename = NULL; +static dns_name_t tmpzonename; +static dns_name_t restart_master; +static dns_tsig_keyring_t *gssring = NULL; +static dns_tsigkey_t *tsigkey = NULL; +static dst_key_t *sig0key; +static lwres_context_t *lwctx = NULL; +static lwres_conf_t *lwconf; +static isc_sockaddr_t *servers; +static int ns_inuse = 0; +static int ns_total = 0; +static isc_sockaddr_t *userserver = NULL; +static isc_sockaddr_t *localaddr = NULL; +static isc_sockaddr_t *serveraddr = NULL; +static isc_sockaddr_t tempaddr; +static char *keystr = NULL, *keyfile = NULL; +static isc_entropy_t *entropy = NULL; +static isc_boolean_t shuttingdown = ISC_FALSE; +static FILE *input; +static isc_boolean_t interactive = ISC_TRUE; +static isc_boolean_t seenerror = ISC_FALSE; +static const dns_master_style_t *style; +static int requests = 0; +static unsigned int logdebuglevel = 0; +static unsigned int timeout = 300; +static unsigned int udp_timeout = 3; +static unsigned int udp_retries = 3; +static dns_rdataclass_t defaultclass = dns_rdataclass_in; +static dns_rdataclass_t zoneclass = dns_rdataclass_none; +static dns_message_t *answer = NULL; + +typedef struct nsu_requestinfo { + dns_message_t *msg; + isc_sockaddr_t *addr; +} nsu_requestinfo_t; + +static void +sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, + dns_message_t *msg, dns_request_t **request); +static void +fatal(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +static void +debug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +static void +ddebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +#ifdef GSSAPI +static dns_fixedname_t fkname; +static isc_sockaddr_t *kserver = NULL; +static char servicename[DNS_NAME_FORMATSIZE]; +static dns_name_t *keyname; +typedef struct nsu_gssinfo { + dns_message_t *msg; + isc_sockaddr_t *addr; + gss_ctx_id_t context; +} nsu_gssinfo_t; + +static void +start_gssrequest(dns_name_t *master); +static void +send_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, + dns_message_t *msg, dns_request_t **request, + gss_ctx_id_t context); +static void +recvgss(isc_task_t *task, isc_event_t *event); +#endif /* GSSAPI */ + +static void +error(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +#define STATUS_MORE (isc_uint16_t)0 +#define STATUS_SEND (isc_uint16_t)1 +#define STATUS_QUIT (isc_uint16_t)2 +#define STATUS_SYNTAX (isc_uint16_t)3 + +typedef struct entropysource entropysource_t; + +struct entropysource { + isc_entropysource_t *source; + isc_mem_t *mctx; + ISC_LINK(entropysource_t) link; +}; + +static ISC_LIST(entropysource_t) sources; + +static void +setup_entropy(isc_mem_t *mctx, const char *randomfile, isc_entropy_t **ectx) +{ + isc_result_t result; + isc_entropysource_t *source = NULL; + entropysource_t *elt; + int usekeyboard = ISC_ENTROPY_KEYBOARDMAYBE; + + REQUIRE(ectx != NULL); + + if (*ectx == NULL) { + result = isc_entropy_create(mctx, ectx); + if (result != ISC_R_SUCCESS) + fatal("could not create entropy object"); + ISC_LIST_INIT(sources); + } + + if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) { + usekeyboard = ISC_ENTROPY_KEYBOARDYES; + randomfile = NULL; + } + + result = isc_entropy_usebestsource(*ectx, &source, randomfile, + usekeyboard); + + if (result != ISC_R_SUCCESS) + fatal("could not initialize entropy source: %s", + isc_result_totext(result)); + + if (source != NULL) { + elt = isc_mem_get(mctx, sizeof(*elt)); + if (elt == NULL) + fatal("out of memory"); + elt->source = source; + elt->mctx = mctx; + ISC_LINK_INIT(elt, link); + ISC_LIST_APPEND(sources, elt, link); + } +} + +static void +cleanup_entropy(isc_entropy_t **ectx) { + entropysource_t *source; + while (!ISC_LIST_EMPTY(sources)) { + source = ISC_LIST_HEAD(sources); + ISC_LIST_UNLINK(sources, source, link); + isc_entropy_destroysource(&source->source); + isc_mem_put(source->mctx, source, sizeof(*source)); + } + isc_entropy_detach(ectx); +} + + +static dns_rdataclass_t +getzoneclass(void) { + if (zoneclass == dns_rdataclass_none) + zoneclass = defaultclass; + return (zoneclass); +} + +static isc_boolean_t +setzoneclass(dns_rdataclass_t rdclass) { + if (zoneclass == dns_rdataclass_none || + rdclass == dns_rdataclass_none) + zoneclass = rdclass; + if (zoneclass != rdclass) + return (ISC_FALSE); + return (ISC_TRUE); +} + +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 void +error(const char *format, ...) { + va_list args; + + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); +} + +static void +debug(const char *format, ...) { + va_list args; + + if (debugging) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + } +} + +static void +ddebug(const char *format, ...) { + va_list args; + + if (ddebugging) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + } +} + +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 * +mem_alloc(void *arg, size_t size) { + return (isc_mem_get(arg, size)); +} + +static void +mem_free(void *arg, void *mem, size_t size) { + isc_mem_put(arg, mem, size); +} + +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 +reset_system(void) { + isc_result_t result; + + ddebug("reset_system()"); + /* If the update message is still around, destroy it */ + if (updatemsg != NULL) + dns_message_reset(updatemsg, DNS_MESSAGE_INTENTRENDER); + else { + result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, + &updatemsg); + check_result(result, "dns_message_create"); + } + updatemsg->opcode = dns_opcode_update; + if (usegsstsig) { + if (tsigkey != NULL) + dns_tsigkey_detach(&tsigkey); + if (gssring != NULL) + dns_tsigkeyring_destroy(&gssring); + tried_other_gsstsig = ISC_FALSE; + } +} + +static isc_uint16_t +parse_hmac(dns_name_t **hmac, const char *hmacstr, size_t len) { + isc_uint16_t digestbits = 0; + isc_result_t result; + char buf[20]; + + REQUIRE(hmac != NULL && *hmac == NULL); + REQUIRE(hmacstr != NULL); + + if (len >= sizeof(buf)) + fatal("unknown key type '%.*s'", (int)(len), hmacstr); + + strncpy(buf, hmacstr, len); + buf[len] = 0; + + if (strcasecmp(buf, "hmac-md5") == 0) { + *hmac = DNS_TSIG_HMACMD5_NAME; + } else if (strncasecmp(buf, "hmac-md5-", 9) == 0) { + *hmac = DNS_TSIG_HMACMD5_NAME; + result = isc_parse_uint16(&digestbits, &buf[9], 10); + if (result != ISC_R_SUCCESS || digestbits > 128) + fatal("digest-bits out of range [0..128]"); + digestbits = (digestbits +7) & ~0x7U; + } else if (strcasecmp(buf, "hmac-sha1") == 0) { + *hmac = DNS_TSIG_HMACSHA1_NAME; + } else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) { + *hmac = DNS_TSIG_HMACSHA1_NAME; + result = isc_parse_uint16(&digestbits, &buf[10], 10); + if (result != ISC_R_SUCCESS || digestbits > 160) + fatal("digest-bits out of range [0..160]"); + digestbits = (digestbits +7) & ~0x7U; + } else if (strcasecmp(buf, "hmac-sha224") == 0) { + *hmac = DNS_TSIG_HMACSHA224_NAME; + } else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) { + *hmac = DNS_TSIG_HMACSHA224_NAME; + result = isc_parse_uint16(&digestbits, &buf[12], 10); + if (result != ISC_R_SUCCESS || digestbits > 224) + fatal("digest-bits out of range [0..224]"); + digestbits = (digestbits +7) & ~0x7U; + } else if (strcasecmp(buf, "hmac-sha256") == 0) { + *hmac = DNS_TSIG_HMACSHA256_NAME; + } else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) { + *hmac = DNS_TSIG_HMACSHA256_NAME; + result = isc_parse_uint16(&digestbits, &buf[12], 10); + if (result != ISC_R_SUCCESS || digestbits > 256) + fatal("digest-bits out of range [0..256]"); + digestbits = (digestbits +7) & ~0x7U; + } else if (strcasecmp(buf, "hmac-sha384") == 0) { + *hmac = DNS_TSIG_HMACSHA384_NAME; + } else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) { + *hmac = DNS_TSIG_HMACSHA384_NAME; + result = isc_parse_uint16(&digestbits, &buf[12], 10); + if (result != ISC_R_SUCCESS || digestbits > 384) + fatal("digest-bits out of range [0..384]"); + digestbits = (digestbits +7) & ~0x7U; + } else if (strcasecmp(buf, "hmac-sha512") == 0) { + *hmac = DNS_TSIG_HMACSHA512_NAME; + } else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) { + *hmac = DNS_TSIG_HMACSHA512_NAME; + result = isc_parse_uint16(&digestbits, &buf[12], 10); + if (result != ISC_R_SUCCESS || digestbits > 512) + fatal("digest-bits out of range [0..512]"); + digestbits = (digestbits +7) & ~0x7U; + } else + fatal("unknown key type '%s'", buf); + return (digestbits); +} + +static void +setup_keystr(void) { + unsigned char *secret = NULL; + int secretlen; + isc_buffer_t secretbuf; + isc_result_t result; + isc_buffer_t keynamesrc; + char *secretstr; + char *s, *n; + dns_fixedname_t fkeyname; + dns_name_t *keyname; + char *name; + dns_name_t *hmacname = NULL; + isc_uint16_t digestbits = 0; + + dns_fixedname_init(&fkeyname); + keyname = dns_fixedname_name(&fkeyname); + + debug("Creating key..."); + + s = strchr(keystr, ':'); + if (s == NULL || s == keystr || s[1] == 0) + fatal("key option must specify [hmac:]keyname:secret"); + secretstr = s + 1; + n = strchr(secretstr, ':'); + if (n != NULL) { + if (n == secretstr || n[1] == 0) + fatal("key option must specify [hmac:]keyname:secret"); + name = secretstr; + secretstr = n + 1; + digestbits = parse_hmac(&hmacname, keystr, s - keystr); + } else { + hmacname = DNS_TSIG_HMACMD5_NAME; + name = keystr; + n = s; + } + + isc_buffer_init(&keynamesrc, name, n - name); + isc_buffer_add(&keynamesrc, n - name); + + debug("namefromtext"); + result = dns_name_fromtext(keyname, &keynamesrc, dns_rootname, + ISC_FALSE, NULL); + check_result(result, "dns_name_fromtext"); + + secretlen = strlen(secretstr) * 3 / 4; + secret = isc_mem_allocate(mctx, secretlen); + if (secret == NULL) + fatal("out of memory"); + + isc_buffer_init(&secretbuf, secret, secretlen); + result = isc_base64_decodestring(secretstr, &secretbuf); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not create key from %s: %s\n", + keystr, isc_result_totext(result)); + goto failure; + } + + secretlen = isc_buffer_usedlength(&secretbuf); + + debug("keycreate"); + result = dns_tsigkey_create(keyname, hmacname, secret, secretlen, + ISC_TRUE, NULL, 0, 0, mctx, NULL, &tsigkey); + if (result != ISC_R_SUCCESS) + fprintf(stderr, "could not create key from %s: %s\n", + keystr, dns_result_totext(result)); + else + dst_key_setbits(tsigkey->key, digestbits); + failure: + if (secret != NULL) + isc_mem_free(mctx, secret); +} + +static void +setup_keyfile(void) { + dst_key_t *dstkey = NULL; + isc_result_t result; + dns_name_t *hmacname = NULL; + + debug("Creating key..."); + + result = dst_key_fromnamedfile(keyfile, + 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)); + return; + } + switch (dst_key_alg(dstkey)) { + case DST_ALG_HMACMD5: + hmacname = DNS_TSIG_HMACMD5_NAME; + break; + case DST_ALG_HMACSHA1: + hmacname = DNS_TSIG_HMACSHA1_NAME; + break; + case DST_ALG_HMACSHA224: + hmacname = DNS_TSIG_HMACSHA224_NAME; + break; + case DST_ALG_HMACSHA256: + hmacname = DNS_TSIG_HMACSHA256_NAME; + break; + case DST_ALG_HMACSHA384: + hmacname = DNS_TSIG_HMACSHA384_NAME; + break; + case DST_ALG_HMACSHA512: + hmacname = DNS_TSIG_HMACSHA512_NAME; + break; + } + if (hmacname != NULL) { + result = dns_tsigkey_createfromkey(dst_key_name(dstkey), + hmacname, dstkey, ISC_FALSE, + NULL, 0, 0, mctx, NULL, + &tsigkey); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not create key from %s: %s\n", + keyfile, isc_result_totext(result)); + dst_key_free(&dstkey); + return; + } + } else + sig0key = dstkey; +} + +static void +doshutdown(void) { + isc_task_detach(&global_task); + + if (userserver != NULL) + isc_mem_put(mctx, userserver, sizeof(isc_sockaddr_t)); + + if (localaddr != NULL) + isc_mem_put(mctx, localaddr, sizeof(isc_sockaddr_t)); + + if (tsigkey != NULL) { + ddebug("Freeing TSIG key"); + dns_tsigkey_detach(&tsigkey); + } + + if (sig0key != NULL) { + ddebug("Freeing SIG(0) key"); + dst_key_free(&sig0key); + } + + if (updatemsg != NULL) + dns_message_destroy(&updatemsg); + + if (is_dst_up) { + ddebug("Destroy DST lib"); + dst_lib_destroy(); + is_dst_up = ISC_FALSE; + } + + cleanup_entropy(&entropy); + + lwres_conf_clear(lwctx); + lwres_context_destroy(&lwctx); + + isc_mem_put(mctx, servers, ns_total * sizeof(isc_sockaddr_t)); + + ddebug("Destroying request manager"); + dns_requestmgr_detach(&requestmgr); + + ddebug("Freeing the dispatchers"); + if (have_ipv4) + dns_dispatch_detach(&dispatchv4); + if (have_ipv6) + dns_dispatch_detach(&dispatchv6); + + ddebug("Shutting down dispatch manager"); + dns_dispatchmgr_destroy(&dispatchmgr); + +} + +static void +maybeshutdown(void) { + ddebug("Shutting down request manager"); + dns_requestmgr_shutdown(requestmgr); + + if (requests != 0) + return; + + doshutdown(); +} + +static void +shutdown_program(isc_task_t *task, isc_event_t *event) { + REQUIRE(task == global_task); + UNUSED(task); + + ddebug("shutdown_program()"); + isc_event_free(&event); + + shuttingdown = ISC_TRUE; + maybeshutdown(); +} + +static void +setup_system(void) { + isc_result_t result; + isc_sockaddr_t bind_any, bind_any6; + lwres_result_t lwresult; + unsigned int attrs, attrmask; + int i; + isc_logconfig_t *logconfig = NULL; + + ddebug("setup_system()"); + + dns_result_register(); + + result = isc_net_probeipv4(); + if (result == ISC_R_SUCCESS) + have_ipv4 = ISC_TRUE; + + result = isc_net_probeipv6(); + if (result == ISC_R_SUCCESS) + have_ipv6 = ISC_TRUE; + + if (!have_ipv4 && !have_ipv6) + fatal("could not find either IPv4 or IPv6"); + + result = isc_log_create(mctx, &lctx, &logconfig); + check_result(result, "isc_log_create"); + + isc_log_setcontext(lctx); + dns_log_init(lctx); + dns_log_setcontext(lctx); + + result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL); + check_result(result, "isc_log_usechannel"); + + isc_log_setdebuglevel(lctx, logdebuglevel); + + lwresult = lwres_context_create(&lwctx, mctx, mem_alloc, mem_free, 1); + if (lwresult != LWRES_R_SUCCESS) + fatal("lwres_context_create failed"); + + (void)lwres_conf_parse(lwctx, RESOLV_CONF); + lwconf = lwres_conf_get(lwctx); + + ns_total = lwconf->nsnext; + if (ns_total <= 0) { + /* No name servers in resolv.conf; default to loopback. */ + struct in_addr localhost; + ns_total = 1; + servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t)); + if (servers == NULL) + fatal("out of memory"); + localhost.s_addr = htonl(INADDR_LOOPBACK); + isc_sockaddr_fromin(&servers[0], &localhost, DNSDEFAULTPORT); + } else { + servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t)); + if (servers == NULL) + fatal("out of memory"); + for (i = 0; i < ns_total; i++) { + if (lwconf->nameservers[i].family == LWRES_ADDRTYPE_V4) { + struct in_addr in4; + memcpy(&in4, lwconf->nameservers[i].address, 4); + isc_sockaddr_fromin(&servers[i], &in4, DNSDEFAULTPORT); + } else { + struct in6_addr in6; + memcpy(&in6, lwconf->nameservers[i].address, 16); + isc_sockaddr_fromin6(&servers[i], &in6, + DNSDEFAULTPORT); + } + } + } + + setup_entropy(mctx, NULL, &entropy); + + result = isc_hash_create(mctx, entropy, DNS_NAME_MAXWIRE); + check_result(result, "isc_hash_create"); + isc_hash_init(); + + result = dns_dispatchmgr_create(mctx, entropy, &dispatchmgr); + check_result(result, "dns_dispatchmgr_create"); + + result = isc_socketmgr_create(mctx, &socketmgr); + check_result(result, "dns_socketmgr_create"); + + result = isc_timermgr_create(mctx, &timermgr); + check_result(result, "dns_timermgr_create"); + + result = isc_taskmgr_create(mctx, 1, 0, &taskmgr); + check_result(result, "isc_taskmgr_create"); + + result = isc_task_create(taskmgr, 0, &global_task); + check_result(result, "isc_task_create"); + + result = isc_task_onshutdown(global_task, shutdown_program, NULL); + check_result(result, "isc_task_onshutdown"); + + result = dst_lib_init(mctx, entropy, 0); + check_result(result, "dst_lib_init"); + is_dst_up = ISC_TRUE; + + attrmask = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP; + attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6; + + if (have_ipv6) { + attrs = DNS_DISPATCHATTR_UDP; + attrs |= DNS_DISPATCHATTR_MAKEQUERY; + attrs |= DNS_DISPATCHATTR_IPV6; + isc_sockaddr_any6(&bind_any6); + result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, + &bind_any6, PACKETSIZE, + 4, 2, 3, 5, + attrs, attrmask, &dispatchv6); + check_result(result, "dns_dispatch_getudp (v6)"); + } + + if (have_ipv4) { + attrs = DNS_DISPATCHATTR_UDP; + attrs |= DNS_DISPATCHATTR_MAKEQUERY; + attrs |= DNS_DISPATCHATTR_IPV4; + isc_sockaddr_any(&bind_any); + result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, + &bind_any, PACKETSIZE, + 4, 2, 3, 5, + attrs, attrmask, &dispatchv4); + check_result(result, "dns_dispatch_getudp (v4)"); + } + + result = dns_requestmgr_create(mctx, timermgr, + socketmgr, taskmgr, dispatchmgr, + dispatchv4, dispatchv6, &requestmgr); + check_result(result, "dns_requestmgr_create"); + + if (keystr != NULL) + setup_keystr(); + else if (keyfile != NULL) + setup_keyfile(); +} + +static void +get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) { + int count; + isc_result_t result; + + isc_app_block(); + result = bind9_getaddresses(host, port, sockaddr, 1, &count); + isc_app_unblock(); + if (result != ISC_R_SUCCESS) + fatal("couldn't get address for '%s': %s", + host, isc_result_totext(result)); + INSIST(count == 1); +} + +#define PARSE_ARGS_FMT "dDMl:y:govk:rR::t:u:" + +static void +pre_parse_args(int argc, char **argv) { + int ch; + + while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) { + switch (ch) { + case 'M': /* was -dm */ + debugging = ISC_TRUE; + ddebugging = ISC_TRUE; + memdebugging = ISC_TRUE; + isc_mem_debugging = ISC_MEM_DEBUGTRACE | + ISC_MEM_DEBUGRECORD; + break; + + case '?': + if (isc_commandline_option != '?') + fprintf(stderr, "%s: invalid argument -%c\n", + argv[0], isc_commandline_option); + fprintf(stderr, "usage: nsupdate [-d] " + "[-g | -o | -y keyname:secret | -k keyfile] " + "[-v] [filename]\n"); + exit(1); + + default: + break; + } + } + isc_commandline_reset = ISC_TRUE; + isc_commandline_index = 1; +} + +static void +parse_args(int argc, char **argv, isc_mem_t *mctx, isc_entropy_t **ectx) { + int ch; + isc_uint32_t i; + isc_result_t result; + + debug("parse_args"); + while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) { + switch (ch) { + case 'd': + debugging = ISC_TRUE; + break; + case 'D': /* was -dd */ + debugging = ISC_TRUE; + ddebugging = ISC_TRUE; + break; + case 'M': + break; + case 'l': + result = isc_parse_uint32(&i, isc_commandline_argument, + 10); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "bad library debug value " + "'%s'\n", isc_commandline_argument); + exit(1); + } + logdebuglevel = i; + break; + case 'y': + keystr = isc_commandline_argument; + break; + case 'v': + usevc = ISC_TRUE; + break; + case 'k': + keyfile = isc_commandline_argument; + break; + case 'g': + usegsstsig = ISC_TRUE; + use_win2k_gsstsig = ISC_FALSE; + break; + case 'o': + usegsstsig = ISC_TRUE; + use_win2k_gsstsig = ISC_TRUE; + break; + case 't': + result = isc_parse_uint32(&timeout, + isc_commandline_argument, 10); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "bad timeout '%s'\n", isc_commandline_argument); + exit(1); + } + if (timeout == 0) + timeout = UINT_MAX; + break; + case 'u': + result = isc_parse_uint32(&udp_timeout, + isc_commandline_argument, 10); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "bad udp timeout '%s'\n", isc_commandline_argument); + exit(1); + } + if (udp_timeout == 0) + udp_timeout = UINT_MAX; + break; + case 'r': + result = isc_parse_uint32(&udp_retries, + isc_commandline_argument, 10); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "bad udp retries '%s'\n", isc_commandline_argument); + exit(1); + } + break; + + case 'R': + setup_entropy(mctx, isc_commandline_argument, ectx); + break; + + default: + fprintf(stderr, "%s: unhandled option: %c\n", + argv[0], isc_commandline_option); + exit(1); + } + } + if (keyfile != NULL && keystr != NULL) { + fprintf(stderr, "%s: cannot specify both -k and -y\n", + argv[0]); + exit(1); + } + +#ifdef GSSAPI + if (usegsstsig && (keyfile != NULL || keystr != NULL)) { + fprintf(stderr, "%s: cannot specify -g with -k or -y\n", + argv[0]); + exit(1); + } +#else + if (usegsstsig) { + fprintf(stderr, "%s: cannot specify -g or -o, " \ + "program not linked with GSS API Library\n", + argv[0]); + exit(1); + } +#endif + + if (argv[isc_commandline_index] != NULL) { + if (strcmp(argv[isc_commandline_index], "-") == 0) { + input = stdin; + } else { + result = isc_stdio_open(argv[isc_commandline_index], + "r", &input); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not open '%s': %s\n", + argv[isc_commandline_index], + isc_result_totext(result)); + exit(1); + } + } + interactive = ISC_FALSE; + } +} + +static isc_uint16_t +parse_name(char **cmdlinep, dns_message_t *msg, dns_name_t **namep) { + isc_result_t result; + char *word; + isc_buffer_t *namebuf = NULL; + isc_buffer_t source; + + word = nsu_strsep(cmdlinep, " \t\r\n"); + if (*word == 0) { + fprintf(stderr, "could not read owner name\n"); + return (STATUS_SYNTAX); + } + + result = dns_message_gettempname(msg, namep); + check_result(result, "dns_message_gettempname"); + result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE); + check_result(result, "isc_buffer_allocate"); + dns_name_init(*namep, NULL); + dns_name_setbuffer(*namep, namebuf); + dns_message_takebuffer(msg, &namebuf); + isc_buffer_init(&source, word, strlen(word)); + isc_buffer_add(&source, strlen(word)); + result = dns_name_fromtext(*namep, &source, dns_rootname, + ISC_FALSE, NULL); + check_result(result, "dns_name_fromtext"); + isc_buffer_invalidate(&source); + return (STATUS_MORE); +} + +static isc_uint16_t +parse_rdata(char **cmdlinep, dns_rdataclass_t rdataclass, + dns_rdatatype_t rdatatype, dns_message_t *msg, + 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 != 0 && isspace((unsigned char)*cmdline)) + cmdline++; + + if (*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_fromregion(rdata, rdataclass, rdatatype, &r); + isc_buffer_free(&buf); + dns_message_takebuffer(msg, &newbuf); + } else { + fprintf(stderr, "invalid rdata format: %s\n", + isc_result_totext(result)); + isc_buffer_free(&buf); + return (STATUS_SYNTAX); + } + } else { + rdata->flags = DNS_RDATA_UPDATE; + } + *cmdlinep = cmdline; + return (STATUS_MORE); +} + +static isc_uint16_t +make_prereq(char *cmdline, isc_boolean_t ispositive, isc_boolean_t isrrset) { + isc_result_t result; + char *word; + dns_name_t *name = NULL; + 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; + isc_uint16_t retval; + + ddebug("make_prereq()"); + + /* + * Read the owner name + */ + retval = parse_name(&cmdline, updatemsg, &name); + if (retval != STATUS_MORE) + return (retval); + + /* + * If this is an rrset prereq, read the class or type. + */ + if (isrrset) { + word = nsu_strsep(&cmdline, " \t\r\n"); + if (*word == 0) { + fprintf(stderr, "could not read class or type\n"); + goto failure; + } + region.base = word; + region.length = strlen(word); + result = dns_rdataclass_fromtext(&rdataclass, ®ion); + if (result == ISC_R_SUCCESS) { + if (!setzoneclass(rdataclass)) { + fprintf(stderr, "class mismatch: %s\n", word); + goto failure; + } + /* + * Now read the type. + */ + word = nsu_strsep(&cmdline, " \t\r\n"); + if (*word == 0) { + fprintf(stderr, "could not read type\n"); + goto failure; + } + 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); + goto failure; + } + } else { + rdataclass = getzoneclass(); + result = dns_rdatatype_fromtext(&rdatatype, ®ion); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "invalid type: %s\n", word); + goto failure; + } + } + } else + rdatatype = dns_rdatatype_any; + + result = dns_message_gettemprdata(updatemsg, &rdata); + check_result(result, "dns_message_gettemprdata"); + + rdata->data = NULL; + rdata->length = 0; + + if (isrrset && ispositive) { + retval = parse_rdata(&cmdline, rdataclass, rdatatype, + updatemsg, rdata); + if (retval != STATUS_MORE) + goto failure; + } else + rdata->flags = DNS_RDATA_UPDATE; + + result = dns_message_gettemprdatalist(updatemsg, &rdatalist); + check_result(result, "dns_message_gettemprdatalist"); + result = dns_message_gettemprdataset(updatemsg, &rdataset); + check_result(result, "dns_message_gettemprdataset"); + 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); + dns_rdataset_init(rdataset); + dns_rdatalist_tordataset(rdatalist, rdataset); + ISC_LIST_INIT(name->list); + ISC_LIST_APPEND(name->list, rdataset, link); + dns_message_addname(updatemsg, name, DNS_SECTION_PREREQUISITE); + return (STATUS_MORE); + + failure: + if (name != NULL) + dns_message_puttempname(updatemsg, &name); + return (STATUS_SYNTAX); +} + +static isc_uint16_t +evaluate_prereq(char *cmdline) { + char *word; + isc_boolean_t ispositive, isrrset; + + ddebug("evaluate_prereq()"); + word = nsu_strsep(&cmdline, " \t\r\n"); + if (*word == 0) { + fprintf(stderr, "could not read operation code\n"); + return (STATUS_SYNTAX); + } + 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); + return (STATUS_SYNTAX); + } + return (make_prereq(cmdline, ispositive, isrrset)); +} + +static isc_uint16_t +evaluate_server(char *cmdline) { + char *word, *server; + long port; + + word = nsu_strsep(&cmdline, " \t\r\n"); + if (*word == 0) { + fprintf(stderr, "could not read server name\n"); + return (STATUS_SYNTAX); + } + server = word; + + word = nsu_strsep(&cmdline, " \t\r\n"); + if (*word == 0) + port = DNSDEFAULTPORT; + else { + char *endp; + port = strtol(word, &endp, 10); + if (*endp != 0) { + fprintf(stderr, "port '%s' is not numeric\n", word); + return (STATUS_SYNTAX); + } else if (port < 1 || port > 65535) { + fprintf(stderr, "port '%s' is out of range " + "(1 to 65535)\n", word); + return (STATUS_SYNTAX); + } + } + + if (userserver == NULL) { + userserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); + if (userserver == NULL) + fatal("out of memory"); + } + + get_address(server, (in_port_t)port, userserver); + + return (STATUS_MORE); +} + +static isc_uint16_t +evaluate_local(char *cmdline) { + char *word, *local; + long port; + struct in_addr in4; + struct in6_addr in6; + + word = nsu_strsep(&cmdline, " \t\r\n"); + if (*word == 0) { + fprintf(stderr, "could not read server name\n"); + return (STATUS_SYNTAX); + } + local = word; + + word = nsu_strsep(&cmdline, " \t\r\n"); + if (*word == 0) + port = 0; + else { + char *endp; + port = strtol(word, &endp, 10); + if (*endp != 0) { + fprintf(stderr, "port '%s' is not numeric\n", word); + return (STATUS_SYNTAX); + } else if (port < 1 || port > 65535) { + fprintf(stderr, "port '%s' is out of range " + "(1 to 65535)\n", word); + return (STATUS_SYNTAX); + } + } + + if (localaddr == NULL) { + localaddr = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); + if (localaddr == NULL) + fatal("out of memory"); + } + + if (have_ipv6 && inet_pton(AF_INET6, local, &in6) == 1) + isc_sockaddr_fromin6(localaddr, &in6, (in_port_t)port); + else if (have_ipv4 && inet_pton(AF_INET, local, &in4) == 1) + isc_sockaddr_fromin(localaddr, &in4, (in_port_t)port); + else { + fprintf(stderr, "invalid address %s", local); + return (STATUS_SYNTAX); + } + + return (STATUS_MORE); +} + +static isc_uint16_t +evaluate_key(char *cmdline) { + char *namestr; + char *secretstr; + isc_buffer_t b; + isc_result_t result; + dns_fixedname_t fkeyname; + dns_name_t *keyname; + int secretlen; + unsigned char *secret = NULL; + isc_buffer_t secretbuf; + dns_name_t *hmacname = NULL; + isc_uint16_t digestbits = 0; + char *n; + + namestr = nsu_strsep(&cmdline, " \t\r\n"); + if (*namestr == 0) { + fprintf(stderr, "could not read key name\n"); + return (STATUS_SYNTAX); + } + + dns_fixedname_init(&fkeyname); + keyname = dns_fixedname_name(&fkeyname); + + n = strchr(namestr, ':'); + if (n != NULL) { + digestbits = parse_hmac(&hmacname, namestr, n - namestr); + namestr = n + 1; + } else + hmacname = DNS_TSIG_HMACMD5_NAME; + + isc_buffer_init(&b, namestr, strlen(namestr)); + isc_buffer_add(&b, strlen(namestr)); + result = dns_name_fromtext(keyname, &b, dns_rootname, ISC_FALSE, NULL); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not parse key name\n"); + return (STATUS_SYNTAX); + } + + secretstr = nsu_strsep(&cmdline, "\r\n"); + if (*secretstr == 0) { + fprintf(stderr, "could not read key secret\n"); + return (STATUS_SYNTAX); + } + secretlen = strlen(secretstr) * 3 / 4; + secret = isc_mem_allocate(mctx, secretlen); + if (secret == NULL) + fatal("out of memory"); + + isc_buffer_init(&secretbuf, secret, secretlen); + result = isc_base64_decodestring(secretstr, &secretbuf); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not create key from %s: %s\n", + secretstr, isc_result_totext(result)); + isc_mem_free(mctx, secret); + return (STATUS_SYNTAX); + } + secretlen = isc_buffer_usedlength(&secretbuf); + + if (tsigkey != NULL) + dns_tsigkey_detach(&tsigkey); + result = dns_tsigkey_create(keyname, hmacname, secret, secretlen, + ISC_TRUE, NULL, 0, 0, mctx, NULL, + &tsigkey); + isc_mem_free(mctx, secret); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not create key from %s %s: %s\n", + namestr, secretstr, dns_result_totext(result)); + return (STATUS_SYNTAX); + } + dst_key_setbits(tsigkey->key, digestbits); + return (STATUS_MORE); +} + +static isc_uint16_t +evaluate_zone(char *cmdline) { + char *word; + isc_buffer_t b; + isc_result_t result; + + word = nsu_strsep(&cmdline, " \t\r\n"); + if (*word == 0) { + fprintf(stderr, "could not read zone name\n"); + return (STATUS_SYNTAX); + } + + dns_fixedname_init(&fuserzone); + userzone = dns_fixedname_name(&fuserzone); + isc_buffer_init(&b, word, strlen(word)); + isc_buffer_add(&b, strlen(word)); + result = dns_name_fromtext(userzone, &b, dns_rootname, ISC_FALSE, + NULL); + if (result != ISC_R_SUCCESS) { + userzone = NULL; /* Lest it point to an invalid name */ + fprintf(stderr, "could not parse zone name\n"); + return (STATUS_SYNTAX); + } + + return (STATUS_MORE); +} + +static isc_uint16_t +evaluate_class(char *cmdline) { + char *word; + isc_textregion_t r; + isc_result_t result; + dns_rdataclass_t rdclass; + + word = nsu_strsep(&cmdline, " \t\r\n"); + if (*word == 0) { + fprintf(stderr, "could not read class name\n"); + return (STATUS_SYNTAX); + } + + r.base = word; + r.length = strlen(word); + result = dns_rdataclass_fromtext(&rdclass, &r); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not parse class name: %s\n", word); + return (STATUS_SYNTAX); + } + switch (rdclass) { + case dns_rdataclass_none: + case dns_rdataclass_any: + case dns_rdataclass_reserved0: + fprintf(stderr, "bad default class: %s\n", word); + return (STATUS_SYNTAX); + default: + defaultclass = rdclass; + } + + return (STATUS_MORE); +} + +static isc_uint16_t +update_addordelete(char *cmdline, isc_boolean_t isdelete) { + isc_result_t result; + dns_name_t *name = NULL; + 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; + isc_uint16_t retval; + + ddebug("update_addordelete()"); + + /* + * Read the owner name. + */ + retval = parse_name(&cmdline, updatemsg, &name); + if (retval != STATUS_MORE) + return (retval); + + result = dns_message_gettemprdata(updatemsg, &rdata); + check_result(result, "dns_message_gettemprdata"); + + rdata->rdclass = 0; + rdata->type = 0; + rdata->data = NULL; + rdata->length = 0; + + /* + * 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 == 0) { + if (!isdelete) { + fprintf(stderr, "could not read owner ttl\n"); + goto failure; + } + 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)); + goto failure; + } + } + + if (isdelete) + ttl = 0; + else if (ttl > TTL_MAX) { + fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n", + word, TTL_MAX); + goto failure; + } + + /* + * Read the class or type. + */ + word = nsu_strsep(&cmdline, " \t\r\n"); + parseclass: + if (*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"); + goto failure; + } + } + region.base = word; + region.length = strlen(word); + rdataclass = dns_rdataclass_any; + result = dns_rdataclass_fromtext(&rdataclass, ®ion); + if (result == ISC_R_SUCCESS && rdataclass != dns_rdataclass_any) { + if (!setzoneclass(rdataclass)) { + fprintf(stderr, "class mismatch: %s\n", word); + goto failure; + } + /* + * Now read the type. + */ + word = nsu_strsep(&cmdline, " \t\r\n"); + if (*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"); + goto failure; + } + } + 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)); + goto failure; + } + } else { + rdataclass = getzoneclass(); + 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)); + goto failure; + } + } + + retval = parse_rdata(&cmdline, rdataclass, rdatatype, updatemsg, + rdata); + if (retval != STATUS_MORE) + goto failure; + + 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"); + goto failure; + } + } + + doneparsing: + + result = dns_message_gettemprdatalist(updatemsg, &rdatalist); + check_result(result, "dns_message_gettemprdatalist"); + result = dns_message_gettemprdataset(updatemsg, &rdataset); + check_result(result, "dns_message_gettemprdataset"); + 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); + dns_rdataset_init(rdataset); + dns_rdatalist_tordataset(rdatalist, rdataset); + ISC_LIST_INIT(name->list); + ISC_LIST_APPEND(name->list, rdataset, link); + dns_message_addname(updatemsg, name, DNS_SECTION_UPDATE); + return (STATUS_MORE); + + failure: + if (name != NULL) + dns_message_puttempname(updatemsg, &name); + dns_message_puttemprdata(updatemsg, &rdata); + return (STATUS_SYNTAX); +} + +static isc_uint16_t +evaluate_update(char *cmdline) { + char *word; + isc_boolean_t isdelete; + + ddebug("evaluate_update()"); + word = nsu_strsep(&cmdline, " \t\r\n"); + if (*word == 0) { + fprintf(stderr, "could not read operation code\n"); + return (STATUS_SYNTAX); + } + if (strcasecmp(word, "delete") == 0) + isdelete = ISC_TRUE; + else if (strcasecmp(word, "add") == 0) + isdelete = ISC_FALSE; + else { + fprintf(stderr, "incorrect operation code: %s\n", word); + return (STATUS_SYNTAX); + } + return (update_addordelete(cmdline, isdelete)); +} + +static void +setzone(dns_name_t *zonename) { + isc_result_t result; + dns_name_t *name = NULL; + dns_rdataset_t *rdataset = NULL; + + result = dns_message_firstname(updatemsg, DNS_SECTION_ZONE); + if (result == ISC_R_SUCCESS) { + dns_message_currentname(updatemsg, DNS_SECTION_ZONE, &name); + dns_message_removename(updatemsg, name, DNS_SECTION_ZONE); + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_HEAD(name->list)) { + ISC_LIST_UNLINK(name->list, rdataset, link); + dns_rdataset_disassociate(rdataset); + dns_message_puttemprdataset(updatemsg, &rdataset); + } + dns_message_puttempname(updatemsg, &name); + } + + if (zonename != NULL) { + result = dns_message_gettempname(updatemsg, &name); + check_result(result, "dns_message_gettempname"); + dns_name_init(name, NULL); + dns_name_clone(zonename, name); + result = dns_message_gettemprdataset(updatemsg, &rdataset); + check_result(result, "dns_message_gettemprdataset"); + dns_rdataset_makequestion(rdataset, getzoneclass(), + dns_rdatatype_soa); + ISC_LIST_INIT(name->list); + ISC_LIST_APPEND(name->list, rdataset, link); + dns_message_addname(updatemsg, name, DNS_SECTION_ZONE); + } +} + +static void +show_message(FILE *stream, dns_message_t *msg, const char *description) { + isc_result_t result; + isc_buffer_t *buf = NULL; + int bufsz; + + ddebug("show_message()"); + + setzone(userzone); + + bufsz = INITTEXT; + do { + if (bufsz > MAXTEXT) { + fprintf(stderr, "could not allocate large enough " + "buffer to display message\n"); + exit(1); + } + if (buf != NULL) + isc_buffer_free(&buf); + result = isc_buffer_allocate(mctx, &buf, bufsz); + check_result(result, "isc_buffer_allocate"); + result = dns_message_totext(msg, style, 0, buf); + bufsz *= 2; + } while (result == ISC_R_NOSPACE); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not convert message to text format.\n"); + isc_buffer_free(&buf); + return; + } + fprintf(stream, "%s\n%.*s", description, + (int)isc_buffer_usedlength(buf), (char*)isc_buffer_base(buf)); + isc_buffer_free(&buf); +} + + +static isc_uint16_t +get_next_command(void) { + char cmdlinebuf[MAXCMD]; + char *cmdline; + char *word; + + ddebug("get_next_command()"); + if (interactive) { + fprintf(stdout, "> "); + fflush(stdout); + } + isc_app_block(); + cmdline = fgets(cmdlinebuf, MAXCMD, input); + isc_app_unblock(); + if (cmdline == NULL) + return (STATUS_QUIT); + word = nsu_strsep(&cmdline, " \t\r\n"); + + if (feof(input)) + return (STATUS_QUIT); + if (*word == 0) + return (STATUS_SEND); + if (word[0] == ';') + return (STATUS_MORE); + if (strcasecmp(word, "quit") == 0) + return (STATUS_QUIT); + if (strcasecmp(word, "prereq") == 0) + return (evaluate_prereq(cmdline)); + if (strcasecmp(word, "update") == 0) + return (evaluate_update(cmdline)); + if (strcasecmp(word, "server") == 0) + return (evaluate_server(cmdline)); + if (strcasecmp(word, "local") == 0) + return (evaluate_local(cmdline)); + if (strcasecmp(word, "zone") == 0) + return (evaluate_zone(cmdline)); + if (strcasecmp(word, "class") == 0) + return (evaluate_class(cmdline)); + if (strcasecmp(word, "send") == 0) + return (STATUS_SEND); + if (strcasecmp(word, "show") == 0) { + show_message(stdout, updatemsg, "Outgoing update query:"); + return (STATUS_MORE); + } + if (strcasecmp(word, "answer") == 0) { + if (answer != NULL) + show_message(stdout, answer, "Answer:"); + return (STATUS_MORE); + } + if (strcasecmp(word, "key") == 0) { + usegsstsig = ISC_FALSE; + return (evaluate_key(cmdline)); + } + if (strcasecmp(word, "gsstsig") == 0) { +#ifdef GSSAPI + usegsstsig = ISC_TRUE; + use_win2k_gsstsig = ISC_FALSE; +#else + fprintf(stderr, "gsstsig not supported\n"); +#endif + return (STATUS_MORE); + } + if (strcasecmp(word, "oldgsstsig") == 0) { +#ifdef GSSAPI + usegsstsig = ISC_TRUE; + use_win2k_gsstsig = ISC_TRUE; +#else + fprintf(stderr, "gsstsig not supported\n"); +#endif + return (STATUS_MORE); + } + if (strcasecmp(word, "help") == 0) { + fprintf(stdout, +"local address [port] (set local resolver)\n" +"server address [port] (set master server for zone)\n" +"send (send the update request)\n" +"show (show the update request)\n" +"answer (show the answer to the last request)\n" +"quit (quit, any pending update is not sent\n" +"help (display this message_\n" +"key [hmac:]keyname secret (use TSIG to sign the request)\n" +"gsstsig (use GSS_TSIG to sign the request)\n" +"oldgsstsig (use Microsoft's GSS_TSIG to sign the request)\n" +"zone name (set the zone to be updated)\n" +"class CLASS (set the zone's DNS class, e.g. IN (default), CH)\n" +"prereq nxdomain name (does this name not exist)\n" +"prereq yxdomain name (does this name exist)\n" +"prereq nxrrset .... (does this RRset exist)\n" +"prereq yxrrset .... (does this RRset not exist)\n" +"update add .... (add the given record to the zone)\n" +"update delete .... (remove the given record(s) from the zone)\n"); + return (STATUS_MORE); + } + fprintf(stderr, "incorrect section name: %s\n", word); + return (STATUS_SYNTAX); +} + +static isc_boolean_t +user_interaction(void) { + isc_uint16_t result = STATUS_MORE; + + ddebug("user_interaction()"); + while ((result == STATUS_MORE) || (result == STATUS_SYNTAX)) { + result = get_next_command(); + if (!interactive && result == STATUS_SYNTAX) + fatal("syntax error"); + } + if (result == STATUS_SEND) + return (ISC_TRUE); + return (ISC_FALSE); + +} + +static void +done_update(void) { + isc_event_t *event = global_event; + ddebug("done_update()"); + isc_task_send(global_task, &event); +} + +static void +check_tsig_error(dns_rdataset_t *rdataset, isc_buffer_t *b) { + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_any_tsig_t tsig; + + result = dns_rdataset_first(rdataset); + check_result(result, "dns_rdataset_first"); + dns_rdataset_current(rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &tsig, NULL); + check_result(result, "dns_rdata_tostruct"); + if (tsig.error != 0) { + if (isc_buffer_remaininglength(b) < 1) + check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength"); + isc__buffer_putstr(b, "(" /*)*/); + result = dns_tsigrcode_totext(tsig.error, b); + check_result(result, "dns_tsigrcode_totext"); + if (isc_buffer_remaininglength(b) < 1) + check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength"); + isc__buffer_putstr(b, /*(*/ ")"); + } +} + +static void +update_completed(isc_task_t *task, isc_event_t *event) { + dns_requestevent_t *reqev = NULL; + isc_result_t result; + dns_request_t *request; + + UNUSED(task); + + ddebug("update_completed()"); + + requests--; + + REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); + reqev = (dns_requestevent_t *)event; + request = reqev->request; + + if (shuttingdown) { + dns_request_destroy(&request); + isc_event_free(&event); + maybeshutdown(); + return; + } + + if (reqev->result != ISC_R_SUCCESS) { + fprintf(stderr, "; Communication with server failed: %s\n", + isc_result_totext(reqev->result)); + seenerror = ISC_TRUE; + goto done; + } + + result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &answer); + check_result(result, "dns_message_create"); + result = dns_request_getresponse(request, answer, + DNS_MESSAGEPARSE_PRESERVEORDER); + switch (result) { + case ISC_R_SUCCESS: + if (answer->verify_attempted) + ddebug("tsig verification successful"); + break; + case DNS_R_CLOCKSKEW: + case DNS_R_EXPECTEDTSIG: + case DNS_R_TSIGERRORSET: + case DNS_R_TSIGVERIFYFAILURE: + case DNS_R_UNEXPECTEDTSIG: + case ISC_R_FAILURE: +#if 0 + if (usegsstsig && answer->rcode == dns_rcode_noerror) { + /* + * For MS DNS that violates RFC 2845, section 4.2 + */ + break; + } +#endif + fprintf(stderr, "; TSIG error with server: %s\n", + isc_result_totext(result)); + seenerror = ISC_TRUE; + break; + default: + check_result(result, "dns_request_getresponse"); + } + + if (answer->rcode != dns_rcode_noerror) { + seenerror = ISC_TRUE; + if (!debugging) { + char buf[64]; + isc_buffer_t b; + dns_rdataset_t *rds; + + isc_buffer_init(&b, buf, sizeof(buf) - 1); + result = dns_rcode_totext(answer->rcode, &b); + check_result(result, "dns_rcode_totext"); + rds = dns_message_gettsig(answer, NULL); + if (rds != NULL) + check_tsig_error(rds, &b); + fprintf(stderr, "update failed: %.*s\n", + (int)isc_buffer_usedlength(&b), buf); + } + } + if (debugging) + show_message(stderr, answer, "\nReply from update query:"); + + done: + dns_request_destroy(&request); + if (usegsstsig) { + dns_name_free(&tmpzonename, mctx); + dns_name_free(&restart_master, mctx); + } + isc_event_free(&event); + done_update(); +} + +static void +send_update(dns_name_t *zonename, isc_sockaddr_t *master, + isc_sockaddr_t *srcaddr) +{ + isc_result_t result; + dns_request_t *request = NULL; + unsigned int options = 0; + + ddebug("send_update()"); + + setzone(zonename); + + if (usevc) + options |= DNS_REQUESTOPT_TCP; + if (tsigkey == NULL && sig0key != NULL) { + result = dns_message_setsig0key(updatemsg, sig0key); + check_result(result, "dns_message_setsig0key"); + } + if (debugging) { + char addrbuf[ISC_SOCKADDR_FORMATSIZE]; + + isc_sockaddr_format(master, addrbuf, sizeof(addrbuf)); + fprintf(stderr, "Sending update to %s\n", addrbuf); + } + + result = dns_request_createvia3(requestmgr, updatemsg, srcaddr, + master, options, tsigkey, timeout, + udp_timeout, udp_retries, global_task, + update_completed, NULL, &request); + check_result(result, "dns_request_createvia3"); + + if (debugging) + show_message(stdout, updatemsg, "Outgoing update query:"); + + requests++; +} + +static void +recvsoa(isc_task_t *task, isc_event_t *event) { + dns_requestevent_t *reqev = NULL; + dns_request_t *request = NULL; + isc_result_t result, eresult; + dns_message_t *rcvmsg = NULL; + dns_section_t section; + dns_name_t *name = NULL; + dns_rdataset_t *soaset = NULL; + dns_rdata_soa_t soa; + dns_rdata_t soarr = DNS_RDATA_INIT; + int pass = 0; + dns_name_t master; + nsu_requestinfo_t *reqinfo; + dns_message_t *soaquery = NULL; + isc_sockaddr_t *addr; + isc_boolean_t seencname = ISC_FALSE; + dns_name_t tname; + unsigned int nlabels; + + UNUSED(task); + + ddebug("recvsoa()"); + + requests--; + + REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); + reqev = (dns_requestevent_t *)event; + request = reqev->request; + eresult = reqev->result; + reqinfo = reqev->ev_arg; + soaquery = reqinfo->msg; + addr = reqinfo->addr; + + if (shuttingdown) { + dns_request_destroy(&request); + dns_message_destroy(&soaquery); + isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); + isc_event_free(&event); + maybeshutdown(); + return; + } + + if (eresult != ISC_R_SUCCESS) { + char addrbuf[ISC_SOCKADDR_FORMATSIZE]; + + isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); + fprintf(stderr, "; Communication with %s failed: %s\n", + addrbuf, isc_result_totext(eresult)); + if (userserver != NULL) + fatal("could not talk to specified name server"); + else if (++ns_inuse >= lwconf->nsnext) + fatal("could not talk to any default name server"); + ddebug("Destroying request [%p]", request); + dns_request_destroy(&request); + dns_message_renderreset(soaquery); + dns_message_settsigkey(soaquery, NULL); + sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); + isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); + isc_event_free(&event); + setzoneclass(dns_rdataclass_none); + return; + } + + isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); + reqinfo = NULL; + isc_event_free(&event); + reqev = NULL; + + ddebug("About to create rcvmsg"); + result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg); + check_result(result, "dns_message_create"); + result = dns_request_getresponse(request, rcvmsg, + DNS_MESSAGEPARSE_PRESERVEORDER); + if (result == DNS_R_TSIGERRORSET && userserver != NULL) { + dns_message_destroy(&rcvmsg); + ddebug("Destroying request [%p]", request); + dns_request_destroy(&request); + reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t)); + if (reqinfo == NULL) + fatal("out of memory"); + reqinfo->msg = soaquery; + reqinfo->addr = addr; + dns_message_renderreset(soaquery); + ddebug("retrying soa request without TSIG"); + result = dns_request_createvia3(requestmgr, soaquery, + localaddr, addr, 0, NULL, + FIND_TIMEOUT * 20, + FIND_TIMEOUT, 3, + global_task, recvsoa, reqinfo, + &request); + check_result(result, "dns_request_createvia"); + requests++; + return; + } + check_result(result, "dns_request_getresponse"); + section = DNS_SECTION_ANSWER; + if (debugging) + show_message(stderr, rcvmsg, "Reply from SOA query:"); + + if (rcvmsg->rcode != dns_rcode_noerror && + rcvmsg->rcode != dns_rcode_nxdomain) + fatal("response to SOA query was unsuccessful"); + + if (userzone != NULL && rcvmsg->rcode == dns_rcode_nxdomain) { + char namebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(userzone, namebuf, sizeof(namebuf)); + error("specified zone '%s' does not exist (NXDOMAIN)", + namebuf); + dns_message_destroy(&rcvmsg); + dns_request_destroy(&request); + dns_message_destroy(&soaquery); + ddebug("Out of recvsoa"); + done_update(); + return; + } + + lookforsoa: + if (pass == 0) + section = DNS_SECTION_ANSWER; + else if (pass == 1) + section = DNS_SECTION_AUTHORITY; + else + goto droplabel; + + 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) + goto droplabel; + + if (debugging) { + char namestr[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namestr, sizeof(namestr)); + fprintf(stderr, "Found zone name: %s\n", namestr); + } + + result = dns_rdataset_first(soaset); + check_result(result, "dns_rdataset_first"); + + dns_rdata_init(&soarr); + dns_rdataset_current(soaset, &soarr); + result = dns_rdata_tostruct(&soarr, &soa, NULL); + check_result(result, "dns_rdata_tostruct"); + + dns_name_init(&master, NULL); + dns_name_clone(&soa.origin, &master); + + if (userzone != NULL) + zonename = userzone; + else + zonename = name; + + if (debugging) { + char namestr[DNS_NAME_FORMATSIZE]; + dns_name_format(&master, namestr, sizeof(namestr)); + fprintf(stderr, "The master is: %s\n", namestr); + } + + if (userserver != NULL) + serveraddr = userserver; + else { + char serverstr[DNS_NAME_MAXTEXT+1]; + isc_buffer_t buf; + + isc_buffer_init(&buf, serverstr, sizeof(serverstr)); + result = dns_name_totext(&master, ISC_TRUE, &buf); + check_result(result, "dns_name_totext"); + serverstr[isc_buffer_usedlength(&buf)] = 0; + get_address(serverstr, DNSDEFAULTPORT, &tempaddr); + serveraddr = &tempaddr; + } + dns_rdata_freestruct(&soa); + +#ifdef GSSAPI + if (usegsstsig) { + dns_name_init(&tmpzonename, NULL); + dns_name_dup(zonename, mctx, &tmpzonename); + dns_name_init(&restart_master, NULL); + dns_name_dup(&master, mctx, &restart_master); + start_gssrequest(&master); + } else { + send_update(zonename, serveraddr, localaddr); + setzoneclass(dns_rdataclass_none); + } +#else + send_update(zonename, serveraddr, localaddr); + setzoneclass(dns_rdataclass_none); +#endif + + dns_message_destroy(&soaquery); + dns_request_destroy(&request); + + out: + dns_message_destroy(&rcvmsg); + ddebug("Out of recvsoa"); + return; + + 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) + fatal("could not find enclosing zone"); + dns_name_init(&tname, NULL); + dns_name_getlabelsequence(name, 1, nlabels - 1, &tname); + dns_name_clone(&tname, name); + dns_request_destroy(&request); + dns_message_renderreset(soaquery); + dns_message_settsigkey(soaquery, NULL); + if (userserver != NULL) + sendrequest(localaddr, userserver, soaquery, &request); + else + sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); + goto out; +} + +static void +sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, + dns_message_t *msg, dns_request_t **request) +{ + isc_result_t result; + nsu_requestinfo_t *reqinfo; + + reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t)); + if (reqinfo == NULL) + fatal("out of memory"); + reqinfo->msg = msg; + reqinfo->addr = destaddr; + result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, 0, + (userserver != NULL) ? tsigkey : NULL, + FIND_TIMEOUT * 20, FIND_TIMEOUT, 3, + global_task, recvsoa, reqinfo, request); + check_result(result, "dns_request_createvia"); + requests++; +} + +#ifdef GSSAPI +static void +start_gssrequest(dns_name_t *master) +{ + gss_ctx_id_t context; + isc_buffer_t buf; + isc_result_t result; + isc_uint32_t val = 0; + dns_message_t *rmsg; + dns_request_t *request = NULL; + dns_name_t *servname; + dns_fixedname_t fname; + char namestr[DNS_NAME_FORMATSIZE]; + char keystr[DNS_NAME_FORMATSIZE]; + + debug("start_gssrequest"); + usevc = ISC_TRUE; + + if (gssring != NULL) + dns_tsigkeyring_destroy(&gssring); + gssring = NULL; + result = dns_tsigkeyring_create(mctx, &gssring); + + if (result != ISC_R_SUCCESS) + fatal("dns_tsigkeyring_create failed: %s", + isc_result_totext(result)); + + dns_name_format(master, namestr, sizeof(namestr)); + if (kserver == NULL) { + kserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); + if (kserver == NULL) + fatal("out of memory"); + } + if (userserver == NULL) + get_address(namestr, DNSDEFAULTPORT, kserver); + else + (void)memcpy(kserver, userserver, sizeof(isc_sockaddr_t)); + + dns_fixedname_init(&fname); + servname = dns_fixedname_name(&fname); + + result = isc_string_printf(servicename, sizeof(servicename), + "DNS/%s", namestr); + if (result != ISC_R_SUCCESS) + fatal("isc_string_printf(servicename) failed: %s", + isc_result_totext(result)); + isc_buffer_init(&buf, servicename, strlen(servicename)); + isc_buffer_add(&buf, strlen(servicename)); + result = dns_name_fromtext(servname, &buf, dns_rootname, + ISC_FALSE, NULL); + if (result != ISC_R_SUCCESS) + fatal("dns_name_fromtext(servname) failed: %s", + isc_result_totext(result)); + + dns_fixedname_init(&fkname); + keyname = dns_fixedname_name(&fkname); + + isc_random_get(&val); + result = isc_string_printf(keystr, sizeof(keystr), "%u.sig-%s", + val, namestr); + if (result != ISC_R_SUCCESS) + fatal("isc_string_printf(keystr) failed: %s", + isc_result_totext(result)); + isc_buffer_init(&buf, keystr, strlen(keystr)); + isc_buffer_add(&buf, strlen(keystr)); + + result = dns_name_fromtext(keyname, &buf, dns_rootname, + ISC_FALSE, NULL); + if (result != ISC_R_SUCCESS) + fatal("dns_name_fromtext(keyname) failed: %s", + isc_result_totext(result)); + + /* Windows doesn't recognize name compression in the key name. */ + keyname->attributes |= DNS_NAMEATTR_NOCOMPRESS; + + rmsg = NULL; + result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &rmsg); + if (result != ISC_R_SUCCESS) + fatal("dns_message_create failed: %s", + isc_result_totext(result)); + + /* Build first request. */ + + context = GSS_C_NO_CONTEXT; + result = dns_tkey_buildgssquery(rmsg, keyname, servname, NULL, 0, + &context, use_win2k_gsstsig); + if (result == ISC_R_FAILURE) + fatal("Check your Kerberos ticket, it may have expired."); + if (result != ISC_R_SUCCESS) + fatal("dns_tkey_buildgssquery failed: %s", + isc_result_totext(result)); + + send_gssrequest(localaddr, kserver, rmsg, &request, context); +} + +static void +send_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, + dns_message_t *msg, dns_request_t **request, + gss_ctx_id_t context) +{ + isc_result_t result; + nsu_gssinfo_t *reqinfo; + unsigned int options = 0; + + debug("send_gssrequest"); + reqinfo = isc_mem_get(mctx, sizeof(nsu_gssinfo_t)); + if (reqinfo == NULL) + fatal("out of memory"); + reqinfo->msg = msg; + reqinfo->addr = destaddr; + reqinfo->context = context; + + options |= DNS_REQUESTOPT_TCP; + result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, + options, tsigkey, FIND_TIMEOUT * 20, + FIND_TIMEOUT, 3, global_task, recvgss, + reqinfo, request); + check_result(result, "dns_request_createvia3"); + if (debugging) + show_message(stdout, msg, "Outgoing update query:"); + requests++; +} + +static void +recvgss(isc_task_t *task, isc_event_t *event) { + dns_requestevent_t *reqev = NULL; + dns_request_t *request = NULL; + isc_result_t result, eresult; + dns_message_t *rcvmsg = NULL; + nsu_gssinfo_t *reqinfo; + dns_message_t *tsigquery = NULL; + isc_sockaddr_t *addr; + gss_ctx_id_t context; + isc_buffer_t buf; + dns_name_t *servname; + dns_fixedname_t fname; + + UNUSED(task); + + ddebug("recvgss()"); + + requests--; + + REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); + reqev = (dns_requestevent_t *)event; + request = reqev->request; + eresult = reqev->result; + reqinfo = reqev->ev_arg; + tsigquery = reqinfo->msg; + context = reqinfo->context; + addr = reqinfo->addr; + + if (shuttingdown) { + dns_request_destroy(&request); + dns_message_destroy(&tsigquery); + isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t)); + isc_event_free(&event); + maybeshutdown(); + return; + } + + if (eresult != ISC_R_SUCCESS) { + char addrbuf[ISC_SOCKADDR_FORMATSIZE]; + + isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); + fprintf(stderr, "; Communication with %s failed: %s\n", + addrbuf, isc_result_totext(eresult)); + if (userserver != NULL) + fatal("could not talk to specified name server"); + else if (++ns_inuse >= lwconf->nsnext) + fatal("could not talk to any default name server"); + ddebug("Destroying request [%p]", request); + dns_request_destroy(&request); + dns_message_renderreset(tsigquery); + sendrequest(localaddr, &servers[ns_inuse], tsigquery, + &request); + isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t)); + isc_event_free(&event); + return; + } + isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t)); + + isc_event_free(&event); + reqev = NULL; + + ddebug("recvgss creating rcvmsg"); + result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg); + check_result(result, "dns_message_create"); + + result = dns_request_getresponse(request, rcvmsg, + DNS_MESSAGEPARSE_PRESERVEORDER); + check_result(result, "dns_request_getresponse"); + + if (debugging) + show_message(stderr, rcvmsg, + "recvmsg reply from GSS-TSIG query"); + + if (rcvmsg->rcode == dns_rcode_formerr && !tried_other_gsstsig) { + ddebug("recvgss trying %s GSS-TSIG", + use_win2k_gsstsig ? "Standard" : "Win2k"); + if (use_win2k_gsstsig) + use_win2k_gsstsig = ISC_FALSE; + else + use_win2k_gsstsig = ISC_TRUE; + tried_other_gsstsig = ISC_TRUE; + start_gssrequest(&restart_master); + goto done; + } + + if (rcvmsg->rcode != dns_rcode_noerror && + rcvmsg->rcode != dns_rcode_nxdomain) + fatal("response to GSS-TSIG query was unsuccessful"); + + + dns_fixedname_init(&fname); + servname = dns_fixedname_name(&fname); + isc_buffer_init(&buf, servicename, strlen(servicename)); + isc_buffer_add(&buf, strlen(servicename)); + result = dns_name_fromtext(servname, &buf, dns_rootname, + ISC_FALSE, NULL); + check_result(result, "dns_name_fromtext"); + + tsigkey = NULL; + result = dns_tkey_gssnegotiate(tsigquery, rcvmsg, servname, + &context, &tsigkey, gssring, + use_win2k_gsstsig); + switch (result) { + + case DNS_R_CONTINUE: + send_gssrequest(localaddr, kserver, tsigquery, &request, + context); + break; + + case ISC_R_SUCCESS: + /* + * XXXSRA Waaay too much fun here. There's no good + * reason why we need a TSIG here (the people who put + * it into the spec admitted at the time that it was + * not a security issue), and Windows clients don't + * seem to work if named complies with the spec and + * includes the gratuitous TSIG. So we're in the + * bizarre situation of having to choose between + * complying with a useless requirement in the spec + * and interoperating. This is nuts. If we can + * confirm this behavior, we should ask the WG to + * consider removing the requirement for the + * gratuitous TSIG here. For the moment, we ignore + * the TSIG -- this too is a spec violation, but it's + * the least insane thing to do. + */ +#if 0 + /* + * Verify the signature. + */ + rcvmsg->state = DNS_SECTION_ANY; + dns_message_setquerytsig(rcvmsg, NULL); + result = dns_message_settsigkey(rcvmsg, tsigkey); + check_result(result, "dns_message_settsigkey"); + result = dns_message_checksig(rcvmsg, NULL); + ddebug("tsig verification: %s", dns_result_totext(result)); + check_result(result, "dns_message_checksig"); +#endif /* 0 */ + + send_update(&tmpzonename, serveraddr, localaddr); + setzoneclass(dns_rdataclass_none); + break; + + default: + fatal("dns_tkey_negotiategss: %s", isc_result_totext(result)); + } + + done: + dns_request_destroy(&request); + dns_message_destroy(&tsigquery); + + dns_message_destroy(&rcvmsg); + ddebug("Out of recvgss"); +} +#endif + +static void +start_update(void) { + isc_result_t result; + dns_rdataset_t *rdataset = NULL; + dns_name_t *name = NULL; + dns_request_t *request = NULL; + dns_message_t *soaquery = NULL; + dns_name_t *firstname; + dns_section_t section = DNS_SECTION_UPDATE; + + ddebug("start_update()"); + + if (answer != NULL) + dns_message_destroy(&answer); + + if (userzone != NULL && userserver != NULL && ! usegsstsig) { + send_update(userzone, userserver, localaddr); + setzoneclass(dns_rdataclass_none); + return; + } + + result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, + &soaquery); + check_result(result, "dns_message_create"); + + if (userserver == NULL) + soaquery->flags |= DNS_MESSAGEFLAG_RD; + + result = dns_message_gettempname(soaquery, &name); + check_result(result, "dns_message_gettempname"); + + result = dns_message_gettemprdataset(soaquery, &rdataset); + check_result(result, "dns_message_gettemprdataset"); + + dns_rdataset_makequestion(rdataset, getzoneclass(), dns_rdatatype_soa); + + if (userzone != NULL) { + dns_name_init(name, NULL); + dns_name_clone(userzone, name); + } else { + result = dns_message_firstname(updatemsg, section); + if (result == ISC_R_NOMORE) { + section = DNS_SECTION_PREREQUISITE; + result = dns_message_firstname(updatemsg, section); + } + if (result != ISC_R_SUCCESS) { + dns_message_puttempname(soaquery, &name); + dns_rdataset_disassociate(rdataset); + dns_message_puttemprdataset(soaquery, &rdataset); + dns_message_destroy(&soaquery); + done_update(); + return; + } + firstname = NULL; + dns_message_currentname(updatemsg, section, &firstname); + dns_name_init(name, NULL); + dns_name_clone(firstname, name); + } + + ISC_LIST_INIT(name->list); + ISC_LIST_APPEND(name->list, rdataset, link); + dns_message_addname(soaquery, name, DNS_SECTION_QUESTION); + + if (userserver != NULL) + sendrequest(localaddr, userserver, soaquery, &request); + else { + ns_inuse = 0; + sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); + } +} + +static void +cleanup(void) { + ddebug("cleanup()"); + + if (answer != NULL) + dns_message_destroy(&answer); + +#ifdef GSSAPI + if (tsigkey != NULL) { + ddebug("detach tsigkey x%p", tsigkey); + dns_tsigkey_detach(&tsigkey); + } + if (gssring != NULL) { + ddebug("Destroying GSS-TSIG keyring"); + dns_tsigkeyring_destroy(&gssring); + } + if (kserver != NULL) { + isc_mem_put(mctx, kserver, sizeof(isc_sockaddr_t)); + kserver = NULL; + } +#endif + + ddebug("Shutting down task manager"); + isc_taskmgr_destroy(&taskmgr); + + ddebug("Destroying event"); + isc_event_free(&global_event); + + ddebug("Shutting down socket manager"); + isc_socketmgr_destroy(&socketmgr); + + ddebug("Shutting down timer manager"); + isc_timermgr_destroy(&timermgr); + + ddebug("Destroying hash context"); + isc_hash_destroy(); + + ddebug("Destroying name state"); + dns_name_destroy(); + + ddebug("Removing log context"); + isc_log_destroy(&lctx); + + ddebug("Destroying memory context"); + if (memdebugging) + isc_mem_stats(mctx, stderr); + isc_mem_destroy(&mctx); +} + +static void +getinput(isc_task_t *task, isc_event_t *event) { + isc_boolean_t more; + + UNUSED(task); + + if (shuttingdown) { + maybeshutdown(); + return; + } + + if (global_event == NULL) + global_event = event; + + reset_system(); + more = user_interaction(); + if (!more) { + isc_app_shutdown(); + return; + } + start_update(); + return; +} + +int +main(int argc, char **argv) { + isc_result_t result; + style = &dns_master_style_debug; + + input = stdin; + + interactive = ISC_TF(isatty(0)); + + isc_app_start(); + + pre_parse_args(argc, argv); + + result = isc_mem_create(0, 0, &mctx); + check_result(result, "isc_mem_create"); + + parse_args(argc, argv, mctx, &entropy); + + setup_system(); + + result = isc_app_onrun(mctx, global_task, getinput, NULL); + check_result(result, "isc_app_onrun"); + + (void)isc_app_run(); + + cleanup(); + + isc_app_finish(); + + if (seenerror) + return (2); + else + return (0); +} diff --git a/contrib/bind-9.5.2/bin/nsupdate/nsupdate.html b/contrib/bind-9.5.2/bin/nsupdate/nsupdate.html new file mode 100644 index 0000000000..522b20fa19 --- /dev/null +++ b/contrib/bind-9.5.2/bin/nsupdate/nsupdate.html @@ -0,0 +1,511 @@ + + + + + +nsupdate + + +
+
+
+

Name

+

nsupdate — Dynamic DNS update utility

+
+
+

Synopsis

+

nsupdate [-d] [[-y [hmac:]keyname:secret] | [-k keyfile]] [-t timeout] [-u udptimeout] [-r udpretries] [-R randomdev] [-v] [filename]

+
+
+

DESCRIPTION

+

nsupdate + is used to submit Dynamic DNS Update requests as defined in RFC2136 + to a name server. + This allows resource records to be added or removed from a zone + without manually editing the zone file. + A single update request can contain requests to add or remove more than + one + resource record. +

+

+ Zones that are under dynamic control via + nsupdate + or a DHCP server should not be edited by hand. + Manual edits could + conflict with dynamic updates and cause data to be lost. +

+

+ The resource records that are dynamically added or removed with + nsupdate + have to be in the same zone. + Requests are sent to the zone's master server. + This is identified by the MNAME field of the zone's SOA record. +

+

+ The + -d + option makes + nsupdate + operate in debug mode. + This provides tracing information about the update requests that are + made and the replies received from the name server. +

+

+ Transaction signatures can be used to authenticate the Dynamic DNS + updates. + These use the TSIG resource record type described in RFC2845 or the + SIG(0) record described in RFC3535 and RFC2931. + TSIG relies on a shared secret that should only be known to + nsupdate and the name server. + Currently, the only supported encryption algorithm for TSIG is + HMAC-MD5, which is defined in RFC 2104. + Once other algorithms are defined for TSIG, applications will need to + ensure they select the appropriate algorithm as well as the key when + authenticating each other. + For instance, suitable + key + and + server + statements would be added to + /etc/named.conf + so that the name server can associate the appropriate secret key + and algorithm with the IP address of the + client application that will be using TSIG authentication. + SIG(0) uses public key cryptography. To use a SIG(0) key, the public + key must be stored in a KEY record in a zone served by the name server. + nsupdate + does not read + /etc/named.conf. +

+

nsupdate + uses the -y or -k option + to provide the shared secret needed to generate a TSIG record + for authenticating Dynamic DNS update requests, default type + HMAC-MD5. These options are mutually exclusive. With the + -k option, nsupdate reads + the shared secret from the file keyfile, + whose name is of the form + K{name}.+157.+{random}.private. For + historical reasons, the file + K{name}.+157.+{random}.key must also be + present. When the -y option is used, a + signature is generated from + [hmac:]keyname:secret. + keyname is the name of the key, and + secret is the base64 encoded shared + secret. Use of the -y option is discouraged + because the shared secret is supplied as a command line + argument in clear text. This may be visible in the output + from + ps(1) or in a history file maintained by the user's + shell. +

+

+ The -k may also be used to specify a SIG(0) key used + to authenticate Dynamic DNS update requests. In this case, the key + specified is not an HMAC-MD5 key. +

+

+ By default, + nsupdate + uses UDP to send update requests to the name server unless they are too + large to fit in a UDP request in which case TCP will be used. + The + -v + option makes + nsupdate + use a TCP connection. + This may be preferable when a batch of update requests is made. +

+

+ The -t option sets the maximum time an update request + can + take before it is aborted. The default is 300 seconds. Zero can be + used + to disable the timeout. +

+

+ The -u option sets the UDP retry interval. The default + is + 3 seconds. If zero, the interval will be computed from the timeout + interval + and number of UDP retries. +

+

+ The -r option sets the number of UDP retries. The + default is + 3. If zero, only one update request will be made. +

+

+ The -R randomdev option + specifies a source of randomness. If the operating system + does not provide a /dev/random or + equivalent device, the default source of randomness is keyboard + input. randomdev specifies the name of + a character device or file containing random data to be used + instead of the default. The special value + keyboard indicates that keyboard input + should be used. This option may be specified multiple times. +

+
+
+

INPUT FORMAT

+

nsupdate + reads input from + filename + or standard input. + Each command is supplied on exactly one line of input. + Some commands are for administrative purposes. + The others are either update instructions or prerequisite checks on the + contents of the zone. + These checks set conditions that some name or set of + resource records (RRset) either exists or is absent from the zone. + These conditions must be met if the entire update request is to succeed. + Updates will be rejected if the tests for the prerequisite conditions + fail. +

+

+ Every update request consists of zero or more prerequisites + and zero or more updates. + This allows a suitably authenticated update request to proceed if some + specified resource records are present or missing from the zone. + A blank input line (or the send command) + causes the + accumulated commands to be sent as one Dynamic DNS update request to the + name server. +

+

+ The command formats and their meaning are as follows: +

+
+
+ server + {servername} + [port] +
+

+ Sends all dynamic update requests to the name server + servername. + When no server statement is provided, + nsupdate + will send updates to the master server of the correct zone. + The MNAME field of that zone's SOA record will identify the + master + server for that zone. + port + is the port number on + servername + where the dynamic update requests get sent. + If no port number is specified, the default DNS port number of + 53 is + used. +

+
+ local + {address} + [port] +
+

+ Sends all dynamic update requests using the local + address. + + When no local statement is provided, + nsupdate + will send updates using an address and port chosen by the + system. + port + can additionally be used to make requests come from a specific + port. + If no port number is specified, the system will assign one. +

+
+ zone + {zonename} +
+

+ Specifies that all updates are to be made to the zone + zonename. + If no + zone + statement is provided, + nsupdate + will attempt determine the correct zone to update based on the + rest of the input. +

+
+ class + {classname} +
+

+ Specify the default class. + If no class is specified, the + default class is + IN. +

+
+ key + {name} + {secret} +
+

+ Specifies that all updates are to be TSIG-signed using the + keyname keysecret pair. + The key command + overrides any key specified on the command line via + -y or -k. +

+
+ prereq nxdomain + {domain-name} +
+

+ Requires that no resource record of any type exists with name + domain-name. +

+
+ prereq yxdomain + {domain-name} +
+

+ Requires that + domain-name + exists (has as at least one resource record, of any type). +

+
+ prereq nxrrset + {domain-name} + [class] + {type} +
+

+ Requires that no resource record exists of the specified + type, + class + and + domain-name. + If + class + is omitted, IN (internet) is assumed. +

+
+ prereq yxrrset + {domain-name} + [class] + {type} +
+

+ This requires that a resource record of the specified + type, + class + and + domain-name + must exist. + If + class + is omitted, IN (internet) is assumed. +

+
+ prereq yxrrset + {domain-name} + [class] + {type} + {data...} +
+

+ The + data + from each set of prerequisites of this form + sharing a common + type, + class, + and + domain-name + are combined to form a set of RRs. This set of RRs must + exactly match the set of RRs existing in the zone at the + given + type, + class, + and + domain-name. + The + data + are written in the standard text representation of the resource + record's + RDATA. +

+
+ update delete + {domain-name} + [ttl] + [class] + [type [data...]] +
+

+ Deletes any resource records named + domain-name. + If + type + and + data + is provided, only matching resource records will be removed. + The internet class is assumed if + class + is not supplied. The + ttl + is ignored, and is only allowed for compatibility. +

+
+ update add + {domain-name} + {ttl} + [class] + {type} + {data...} +
+

+ Adds a new resource record with the specified + ttl, + class + and + data. +

+
+ show +
+

+ Displays the current message, containing all of the + prerequisites and + updates specified since the last send. +

+
+ send +
+

+ Sends the current message. This is equivalent to entering a + blank line. +

+
+ answer +
+

+ Displays the answer. +

+
+

+

+

+ Lines beginning with a semicolon are comments and are ignored. +

+
+
+

EXAMPLES

+

+ The examples below show how + nsupdate + could be used to insert and delete resource records from the + example.com + zone. + Notice that the input in each example contains a trailing blank line so + that + a group of commands are sent as one dynamic update request to the + master name server for + example.com. + +

+
+# nsupdate
+> update delete oldhost.example.com A
+> update add newhost.example.com 86400 A 172.16.1.1
+> send
+
+

+

+

+ Any A records for + oldhost.example.com + are deleted. + And an A record for + newhost.example.com + with IP address 172.16.1.1 is added. + The newly-added record has a 1 day TTL (86400 seconds). +

+
+# nsupdate
+> prereq nxdomain nickname.example.com
+> update add nickname.example.com 86400 CNAME somehost.example.com
+> send
+
+

+

+

+ The prerequisite condition gets the name server to check that there + are no resource records of any type for + nickname.example.com. + + If there are, the update request fails. + If this name does not exist, a CNAME for it is added. + This ensures that when the CNAME is added, it cannot conflict with the + long-standing rule in RFC1034 that a name must not exist as any other + record type if it exists as a CNAME. + (The rule has been updated for DNSSEC in RFC2535 to allow CNAMEs to have + RRSIG, DNSKEY and NSEC records.) +

+
+
+

FILES

+
+
/etc/resolv.conf
+

+ used to identify default name server +

+
K{name}.+157.+{random}.key
+

+ base-64 encoding of HMAC-MD5 key created by + dnssec-keygen(8). +

+
K{name}.+157.+{random}.private
+

+ base-64 encoding of HMAC-MD5 key created by + dnssec-keygen(8). +

+
+
+
+

SEE ALSO

+

RFC2136, + RFC3007, + RFC2104, + RFC2845, + RFC1034, + RFC2535, + RFC2931, + named(8), + dnssec-keygen(8). +

+
+
+

BUGS

+

+ The TSIG key is redundantly stored in two separate files. + This is a consequence of nsupdate using the DST library + for its cryptographic operations, and may change in future + releases. +

+
+
+ diff --git a/contrib/bind-9.5.2/bin/rndc/include/rndc/os.h b/contrib/bind-9.5.2/bin/rndc/include/rndc/os.h new file mode 100644 index 0000000000..e48ee5119b --- /dev/null +++ b/contrib/bind-9.5.2/bin/rndc/include/rndc/os.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2004, 2005, 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 + * 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: os.h,v 1.9.128.2 2009/01/19 23:47:01 tbox Exp $ */ + +/*! \file */ + +#ifndef RNDC_OS_H +#define RNDC_OS_H 1 + +#include +#include + +ISC_LANG_BEGINDECLS + +FILE *safe_create(const char *filename); +/*%< + * Open 'filename' for writing, truncate if necessary. If the file was + * created ensure that only the owner can read/write it. + */ + +int set_user(FILE *fd, const char *user); +/*%< + * Set the owner of the file referenced by 'fd' to 'user'. + * Returns: + * 0 success + * -1 insufficient permissions, or 'user' does not exist. + */ + +ISC_LANG_ENDDECLS + +#endif diff --git a/contrib/bind-9.5.2/bin/rndc/rndc-confgen.8 b/contrib/bind-9.5.2/bin/rndc/rndc-confgen.8 new file mode 100644 index 0000000000..405422ac4a --- /dev/null +++ b/contrib/bind-9.5.2/bin/rndc/rndc-confgen.8 @@ -0,0 +1,211 @@ +.\" Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2001, 2003 Internet Software Consortium. +.\" +.\" 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: rndc-confgen.8,v 1.20.214.1 2009/07/11 01:43:30 tbox Exp $ +.\" +.hy 0 +.ad l +.\" Title: rndc\-confgen +.\" Author: +.\" Generator: DocBook XSL Stylesheets v1.71.1 +.\" Date: Aug 27, 2001 +.\" Manual: BIND9 +.\" Source: BIND9 +.\" +.TH "RNDC\-CONFGEN" "8" "Aug 27, 2001" "BIND9" "BIND9" +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.SH "NAME" +rndc\-confgen \- rndc key generation tool +.SH "SYNOPSIS" +.HP 13 +\fBrndc\-confgen\fR [\fB\-a\fR] [\fB\-b\ \fR\fB\fIkeysize\fR\fR] [\fB\-c\ \fR\fB\fIkeyfile\fR\fR] [\fB\-h\fR] [\fB\-k\ \fR\fB\fIkeyname\fR\fR] [\fB\-p\ \fR\fB\fIport\fR\fR] [\fB\-r\ \fR\fB\fIrandomfile\fR\fR] [\fB\-s\ \fR\fB\fIaddress\fR\fR] [\fB\-t\ \fR\fB\fIchrootdir\fR\fR] [\fB\-u\ \fR\fB\fIuser\fR\fR] +.SH "DESCRIPTION" +.PP +\fBrndc\-confgen\fR +generates configuration files for +\fBrndc\fR. It can be used as a convenient alternative to writing the +\fIrndc.conf\fR +file and the corresponding +\fBcontrols\fR +and +\fBkey\fR +statements in +\fInamed.conf\fR +by hand. Alternatively, it can be run with the +\fB\-a\fR +option to set up a +\fIrndc.key\fR +file and avoid the need for a +\fIrndc.conf\fR +file and a +\fBcontrols\fR +statement altogether. +.SH "OPTIONS" +.PP +\-a +.RS 4 +Do automatic +\fBrndc\fR +configuration. This creates a file +\fIrndc.key\fR +in +\fI/etc\fR +(or whatever +\fIsysconfdir\fR +was specified as when +BIND +was built) that is read by both +\fBrndc\fR +and +\fBnamed\fR +on startup. The +\fIrndc.key\fR +file defines a default command channel and authentication key allowing +\fBrndc\fR +to communicate with +\fBnamed\fR +on the local host with no further configuration. +.sp +Running +\fBrndc\-confgen \-a\fR +allows BIND 9 and +\fBrndc\fR +to be used as drop\-in replacements for BIND 8 and +\fBndc\fR, with no changes to the existing BIND 8 +\fInamed.conf\fR +file. +.sp +If a more elaborate configuration than that generated by +\fBrndc\-confgen \-a\fR +is required, for example if rndc is to be used remotely, you should run +\fBrndc\-confgen\fR +without the +\fB\-a\fR +option and set up a +\fIrndc.conf\fR +and +\fInamed.conf\fR +as directed. +.RE +.PP +\-b \fIkeysize\fR +.RS 4 +Specifies the size of the authentication key in bits. Must be between 1 and 512 bits; the default is 128. +.RE +.PP +\-c \fIkeyfile\fR +.RS 4 +Used with the +\fB\-a\fR +option to specify an alternate location for +\fIrndc.key\fR. +.RE +.PP +\-h +.RS 4 +Prints a short summary of the options and arguments to +\fBrndc\-confgen\fR. +.RE +.PP +\-k \fIkeyname\fR +.RS 4 +Specifies the key name of the rndc authentication key. This must be a valid domain name. The default is +\fBrndc\-key\fR. +.RE +.PP +\-p \fIport\fR +.RS 4 +Specifies the command channel port where +\fBnamed\fR +listens for connections from +\fBrndc\fR. The default is 953. +.RE +.PP +\-r \fIrandomfile\fR +.RS 4 +Specifies a source of random data for generating the authorization. If the operating system does not provide a +\fI/dev/random\fR +or equivalent device, the default source of randomness is keyboard input. +\fIrandomdev\fR +specifies the name of a character device or file containing random data to be used instead of the default. The special value +\fIkeyboard\fR +indicates that keyboard input should be used. +.RE +.PP +\-s \fIaddress\fR +.RS 4 +Specifies the IP address where +\fBnamed\fR +listens for command channel connections from +\fBrndc\fR. The default is the loopback address 127.0.0.1. +.RE +.PP +\-t \fIchrootdir\fR +.RS 4 +Used with the +\fB\-a\fR +option to specify a directory where +\fBnamed\fR +will run chrooted. An additional copy of the +\fIrndc.key\fR +will be written relative to this directory so that it will be found by the chrooted +\fBnamed\fR. +.RE +.PP +\-u \fIuser\fR +.RS 4 +Used with the +\fB\-a\fR +option to set the owner of the +\fIrndc.key\fR +file generated. If +\fB\-t\fR +is also specified only the file in the chroot area has its owner changed. +.RE +.SH "EXAMPLES" +.PP +To allow +\fBrndc\fR +to be used with no manual configuration, run +.PP +\fBrndc\-confgen \-a\fR +.PP +To print a sample +\fIrndc.conf\fR +file and corresponding +\fBcontrols\fR +and +\fBkey\fR +statements to be manually inserted into +\fInamed.conf\fR, run +.PP +\fBrndc\-confgen\fR +.SH "SEE ALSO" +.PP +\fBrndc\fR(8), +\fBrndc.conf\fR(5), +\fBnamed\fR(8), +BIND 9 Administrator Reference Manual. +.SH "AUTHOR" +.PP +Internet Systems Consortium +.SH "COPYRIGHT" +Copyright \(co 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") +.br +Copyright \(co 2001, 2003 Internet Software Consortium. +.br diff --git a/contrib/bind-9.5.2/bin/rndc/rndc-confgen.c b/contrib/bind-9.5.2/bin/rndc/rndc-confgen.c new file mode 100644 index 0000000000..c37b7e3a33 --- /dev/null +++ b/contrib/bind-9.5.2/bin/rndc/rndc-confgen.c @@ -0,0 +1,342 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001, 2003 Internet Software Consortium. + * + * 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: rndc-confgen.c,v 1.24.128.2 2008/10/15 23:46:53 tbox Exp $ */ + +/*! \file */ + +/** + * rndc-confgen generates configuration files for rndc. It can be used + * as a convenient alternative to writing the rndc.conf file and the + * corresponding controls and key statements in named.conf by hand. + * Alternatively, it can be run with the -a option to set up a + * rndc.key file and avoid the need for a rndc.conf file and a + * controls statement altogether. + */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "util.h" + +#define DEFAULT_KEYLENGTH 128 /*% Bits. */ +#define DEFAULT_KEYNAME "rndc-key" +#define DEFAULT_SERVER "127.0.0.1" +#define DEFAULT_PORT 953 + +static char program[256]; +const char *progname; + +isc_boolean_t verbose = ISC_FALSE; + +const char *keyfile, *keydef; + +static void +usage(int status) { + + fprintf(stderr, "\ +Usage:\n\ + %s [-a] [-b bits] [-c keyfile] [-k keyname] [-p port] [-r randomfile] \ +[-s addr] [-t chrootdir] [-u user]\n\ + -a: generate just the key clause and write it to keyfile (%s)\n\ + -b bits: from 1 through 512, default %d; total length of the secret\n\ + -c keyfile: specify an alternate key file (requires -a)\n\ + -k keyname: the name as it will be used in named.conf and rndc.conf\n\ + -p port: the port named will listen on and rndc will connect to\n\ + -r randomfile: a file containing random data\n\ + -s addr: the address to which rndc should connect\n\ + -t chrootdir: write a keyfile in chrootdir as well (requires -a)\n\ + -u user: set the keyfile owner to \"user\" (requires -a)\n", + progname, keydef, DEFAULT_KEYLENGTH); + + exit (status); +} + +/*% + * Write an rndc.key file to 'keyfile'. If 'user' is non-NULL, + * make that user the owner of the file. The key will have + * the name 'keyname' and the secret in the buffer 'secret'. + */ +static void +write_key_file(const char *keyfile, const char *user, + const char *keyname, isc_buffer_t *secret ) +{ + FILE *fd; + + fd = safe_create(keyfile); + if (fd == NULL) + fatal( "unable to create \"%s\"\n", keyfile); + if (user != NULL) { + if (set_user(fd, user) == -1) + fatal("unable to set file owner\n"); + } + fprintf(fd, "key \"%s\" {\n\talgorithm hmac-md5;\n" + "\tsecret \"%.*s\";\n};\n", keyname, + (int)isc_buffer_usedlength(secret), + (char *)isc_buffer_base(secret)); + fflush(fd); + if (ferror(fd)) + fatal("write to %s failed\n", keyfile); + if (fclose(fd)) + fatal("fclose(%s) failed\n", keyfile); + fprintf(stderr, "wrote key file \"%s\"\n", keyfile); +} + +int +main(int argc, char **argv) { + isc_boolean_t show_final_mem = ISC_FALSE; + isc_buffer_t key_rawbuffer; + isc_buffer_t key_txtbuffer; + isc_region_t key_rawregion; + isc_mem_t *mctx = NULL; + isc_entropy_t *ectx = NULL; + isc_entropysource_t *entropy_source = NULL; + isc_result_t result = ISC_R_SUCCESS; + dst_key_t *key = NULL; + const char *keyname = NULL; + const char *randomfile = NULL; + const char *serveraddr = NULL; + char key_rawsecret[64]; + char key_txtsecret[256]; + char *p; + int ch; + int port; + int keysize; + int entropy_flags = 0; + int open_keyboard = ISC_ENTROPY_KEYBOARDMAYBE; + struct in_addr addr4_dummy; + struct in6_addr addr6_dummy; + char *chrootdir = NULL; + char *user = NULL; + isc_boolean_t keyonly = ISC_FALSE; + int len; + + keydef = keyfile = RNDC_KEYFILE; + + result = isc_file_progname(*argv, program, sizeof(program)); + if (result != ISC_R_SUCCESS) + memcpy(program, "rndc-confgen", 13); + progname = program; + + keyname = DEFAULT_KEYNAME; + keysize = DEFAULT_KEYLENGTH; + serveraddr = DEFAULT_SERVER; + port = DEFAULT_PORT; + + isc_commandline_errprint = ISC_FALSE; + + while ((ch = isc_commandline_parse(argc, argv, + "ab:c:hk:Mmp:r:s:t:u:Vy")) != -1) { + switch (ch) { + case 'a': + keyonly = ISC_TRUE; + break; + case 'b': + keysize = strtol(isc_commandline_argument, &p, 10); + if (*p != '\0' || keysize < 0) + fatal("-b requires a non-negative number"); + if (keysize < 1 || keysize > 512) + fatal("-b must be in the range 1 through 512"); + break; + case 'c': + keyfile = isc_commandline_argument; + break; + case 'h': + usage(0); + case 'k': + case 'y': /* Compatible with rndc -y. */ + keyname = isc_commandline_argument; + break; + case 'M': + isc_mem_debugging = ISC_MEM_DEBUGTRACE; + break; + + case 'm': + show_final_mem = ISC_TRUE; + break; + case 'p': + port = strtol(isc_commandline_argument, &p, 10); + if (*p != '\0' || port < 0 || port > 65535) + fatal("port '%s' out of range", + isc_commandline_argument); + break; + case 'r': + randomfile = isc_commandline_argument; + break; + case 's': + serveraddr = isc_commandline_argument; + if (inet_pton(AF_INET, serveraddr, &addr4_dummy) != 1 && + inet_pton(AF_INET6, serveraddr, &addr6_dummy) != 1) + fatal("-s should be an IPv4 or IPv6 address"); + break; + case 't': + chrootdir = isc_commandline_argument; + break; + case 'u': + user = isc_commandline_argument; + break; + case 'V': + verbose = ISC_TRUE; + break; + case '?': + if (isc_commandline_option != '?') { + fprintf(stderr, "%s: invalid argument -%c\n", + program, isc_commandline_option); + usage(1); + } else + usage(0); + break; + default: + fprintf(stderr, "%s: unhandled option -%c\n", + program, isc_commandline_option); + exit(1); + } + } + + argc -= isc_commandline_index; + argv += isc_commandline_index; + + if (argc > 0) + usage(1); + + DO("create memory context", isc_mem_create(0, 0, &mctx)); + + DO("create entropy context", isc_entropy_create(mctx, &ectx)); + + if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) { + randomfile = NULL; + open_keyboard = ISC_ENTROPY_KEYBOARDYES; + } + DO("start entropy source", isc_entropy_usebestsource(ectx, + &entropy_source, + randomfile, + open_keyboard)); + + entropy_flags = ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY; + + DO("initialize dst library", dst_lib_init(mctx, ectx, entropy_flags)); + + DO("generate key", dst_key_generate(dns_rootname, DST_ALG_HMACMD5, + keysize, 0, 0, + DNS_KEYPROTO_ANY, + dns_rdataclass_in, mctx, &key)); + + isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret)); + + DO("dump key to buffer", dst_key_tobuffer(key, &key_rawbuffer)); + + isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret)); + isc_buffer_usedregion(&key_rawbuffer, &key_rawregion); + + DO("bsse64 encode secret", isc_base64_totext(&key_rawregion, -1, "", + &key_txtbuffer)); + + /* + * Shut down the entropy source now so the "stop typing" message + * does not muck with the output. + */ + if (entropy_source != NULL) + isc_entropy_destroysource(&entropy_source); + + if (key != NULL) + dst_key_free(&key); + + isc_entropy_detach(&ectx); + dst_lib_destroy(); + + if (keyonly) { + write_key_file(keyfile, chrootdir == NULL ? user : NULL, + keyname, &key_txtbuffer); + + if (chrootdir != NULL) { + char *buf; + len = strlen(chrootdir) + strlen(keyfile) + 2; + buf = isc_mem_get(mctx, len); + if (buf == NULL) + fatal("isc_mem_get(%d) failed\n", len); + snprintf(buf, len, "%s%s%s", chrootdir, + (*keyfile != '/') ? "/" : "", keyfile); + + write_key_file(buf, user, keyname, &key_txtbuffer); + isc_mem_put(mctx, buf, len); + } + } else { + printf("\ +# Start of rndc.conf\n\ +key \"%s\" {\n\ + algorithm hmac-md5;\n\ + secret \"%.*s\";\n\ +};\n\ +\n\ +options {\n\ + default-key \"%s\";\n\ + default-server %s;\n\ + default-port %d;\n\ +};\n\ +# End of rndc.conf\n\ +\n\ +# Use with the following in named.conf, adjusting the allow list as needed:\n\ +# key \"%s\" {\n\ +# algorithm hmac-md5;\n\ +# secret \"%.*s\";\n\ +# };\n\ +# \n\ +# controls {\n\ +# inet %s port %d\n\ +# allow { %s; } keys { \"%s\"; };\n\ +# };\n\ +# End of named.conf\n", + keyname, + (int)isc_buffer_usedlength(&key_txtbuffer), + (char *)isc_buffer_base(&key_txtbuffer), + keyname, serveraddr, port, + keyname, + (int)isc_buffer_usedlength(&key_txtbuffer), + (char *)isc_buffer_base(&key_txtbuffer), + serveraddr, port, serveraddr, keyname); + } + + if (show_final_mem) + isc_mem_stats(mctx, stderr); + + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/contrib/bind-9.5.2/bin/rndc/rndc-confgen.html b/contrib/bind-9.5.2/bin/rndc/rndc-confgen.html new file mode 100644 index 0000000000..0219888027 --- /dev/null +++ b/contrib/bind-9.5.2/bin/rndc/rndc-confgen.html @@ -0,0 +1,188 @@ + + + + + +rndc-confgen + + +
+
+
+

Name

+

rndc-confgen — rndc key generation tool

+
+
+

Synopsis

+

rndc-confgen [-a] [-b keysize] [-c keyfile] [-h] [-k keyname] [-p port] [-r randomfile] [-s address] [-t chrootdir] [-u user]

+
+
+

DESCRIPTION

+

rndc-confgen + generates configuration files + for rndc. It can be used as a + convenient alternative to writing the + rndc.conf file + and the corresponding controls + and key + statements in named.conf by hand. + Alternatively, it can be run with the -a + option to set up a rndc.key file and + avoid the need for a rndc.conf file + and a controls statement altogether. +

+
+
+

OPTIONS

+
+
-a
+
+

+ Do automatic rndc configuration. + This creates a file rndc.key + in /etc (or whatever + sysconfdir + was specified as when BIND was + built) + that is read by both rndc + and named on startup. The + rndc.key file defines a default + command channel and authentication key allowing + rndc to communicate with + named on the local host + with no further configuration. +

+

+ Running rndc-confgen -a allows + BIND 9 and rndc to be used as + drop-in + replacements for BIND 8 and ndc, + with no changes to the existing BIND 8 + named.conf file. +

+

+ If a more elaborate configuration than that + generated by rndc-confgen -a + is required, for example if rndc is to be used remotely, + you should run rndc-confgen without + the + -a option and set up a + rndc.conf and + named.conf + as directed. +

+
+
-b keysize
+

+ Specifies the size of the authentication key in bits. + Must be between 1 and 512 bits; the default is 128. +

+
-c keyfile
+

+ Used with the -a option to specify + an alternate location for rndc.key. +

+
-h
+

+ Prints a short summary of the options and arguments to + rndc-confgen. +

+
-k keyname
+

+ Specifies the key name of the rndc authentication key. + This must be a valid domain name. + The default is rndc-key. +

+
-p port
+

+ Specifies the command channel port where named + listens for connections from rndc. + The default is 953. +

+
-r randomfile
+

+ Specifies a source of random data for generating the + authorization. If the operating + system does not provide a /dev/random + or equivalent device, the default source of randomness + is keyboard input. randomdev + specifies + the name of a character device or file containing random + data to be used instead of the default. The special value + keyboard indicates that keyboard + input should be used. +

+
-s address
+

+ Specifies the IP address where named + listens for command channel connections from + rndc. The default is the loopback + address 127.0.0.1. +

+
-t chrootdir
+

+ Used with the -a option to specify + a directory where named will run + chrooted. An additional copy of the rndc.key + will be written relative to this directory so that + it will be found by the chrooted named. +

+
-u user
+

+ Used with the -a option to set the + owner + of the rndc.key file generated. + If + -t is also specified only the file + in + the chroot area has its owner changed. +

+
+
+
+

EXAMPLES

+

+ To allow rndc to be used with + no manual configuration, run +

+

rndc-confgen -a +

+

+ To print a sample rndc.conf file and + corresponding controls and key + statements to be manually inserted into named.conf, + run +

+

rndc-confgen +

+
+
+

SEE ALSO

+

rndc(8), + rndc.conf(5), + named(8), + BIND 9 Administrator Reference Manual. +

+
+
+

AUTHOR

+

Internet Systems Consortium +

+
+
+ diff --git a/contrib/bind-9.5.2/bin/rndc/rndc.8 b/contrib/bind-9.5.2/bin/rndc/rndc.8 new file mode 100644 index 0000000000..596d8543d4 --- /dev/null +++ b/contrib/bind-9.5.2/bin/rndc/rndc.8 @@ -0,0 +1,148 @@ +.\" Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2000, 2001 Internet Software Consortium. +.\" +.\" 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: rndc.8,v 1.42.10.1 2009/07/11 01:43:29 tbox Exp $ +.\" +.hy 0 +.ad l +.\" Title: rndc +.\" Author: +.\" Generator: DocBook XSL Stylesheets v1.71.1 +.\" Date: June 30, 2000 +.\" Manual: BIND9 +.\" Source: BIND9 +.\" +.TH "RNDC" "8" "June 30, 2000" "BIND9" "BIND9" +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.SH "NAME" +rndc \- name server control utility +.SH "SYNOPSIS" +.HP 5 +\fBrndc\fR [\fB\-b\ \fR\fB\fIsource\-address\fR\fR] [\fB\-c\ \fR\fB\fIconfig\-file\fR\fR] [\fB\-k\ \fR\fB\fIkey\-file\fR\fR] [\fB\-s\ \fR\fB\fIserver\fR\fR] [\fB\-p\ \fR\fB\fIport\fR\fR] [\fB\-V\fR] [\fB\-y\ \fR\fB\fIkey_id\fR\fR] {command} +.SH "DESCRIPTION" +.PP +\fBrndc\fR +controls the operation of a name server. It supersedes the +\fBndc\fR +utility that was provided in old BIND releases. If +\fBrndc\fR +is invoked with no command line options or arguments, it prints a short summary of the supported commands and the available options and their arguments. +.PP +\fBrndc\fR +communicates with the name server over a TCP connection, sending commands authenticated with digital signatures. In the current versions of +\fBrndc\fR +and +\fBnamed\fR, the only supported authentication algorithm is HMAC\-MD5, which uses a shared secret on each end of the connection. This provides TSIG\-style authentication for the command request and the name server's response. All commands sent over the channel must be signed by a key_id known to the server. +.PP +\fBrndc\fR +reads a configuration file to determine how to contact the name server and decide what algorithm and key it should use. +.SH "OPTIONS" +.PP +\-b \fIsource\-address\fR +.RS 4 +Use +\fIsource\-address\fR +as the source address for the connection to the server. Multiple instances are permitted to allow setting of both the IPv4 and IPv6 source addresses. +.RE +.PP +\-c \fIconfig\-file\fR +.RS 4 +Use +\fIconfig\-file\fR +as the configuration file instead of the default, +\fI/etc/rndc.conf\fR. +.RE +.PP +\-k \fIkey\-file\fR +.RS 4 +Use +\fIkey\-file\fR +as the key file instead of the default, +\fI/etc/rndc.key\fR. The key in +\fI/etc/rndc.key\fR +will be used to authenticate commands sent to the server if the +\fIconfig\-file\fR +does not exist. +.RE +.PP +\-s \fIserver\fR +.RS 4 +\fIserver\fR +is the name or address of the server which matches a server statement in the configuration file for +\fBrndc\fR. If no server is supplied on the command line, the host named by the default\-server clause in the options statement of the +\fBrndc\fR +configuration file will be used. +.RE +.PP +\-p \fIport\fR +.RS 4 +Send commands to TCP port +\fIport\fR +instead of BIND 9's default control channel port, 953. +.RE +.PP +\-V +.RS 4 +Enable verbose logging. +.RE +.PP +\-y \fIkey_id\fR +.RS 4 +Use the key +\fIkey_id\fR +from the configuration file. +\fIkey_id\fR +must be known by named with the same algorithm and secret string in order for control message validation to succeed. If no +\fIkey_id\fR +is specified, +\fBrndc\fR +will first look for a key clause in the server statement of the server being used, or if no server statement is present for that host, then the default\-key clause of the options statement. Note that the configuration file contains shared secrets which are used to send authenticated control commands to name servers. It should therefore not have general read or write access. +.RE +.PP +For the complete set of commands supported by +\fBrndc\fR, see the BIND 9 Administrator Reference Manual or run +\fBrndc\fR +without arguments to see its help message. +.SH "LIMITATIONS" +.PP +\fBrndc\fR +does not yet support all the commands of the BIND 8 +\fBndc\fR +utility. +.PP +There is currently no way to provide the shared secret for a +\fBkey_id\fR +without using the configuration file. +.PP +Several error messages could be clearer. +.SH "SEE ALSO" +.PP +\fBrndc.conf\fR(5), +\fBrndc\-confgen\fR(8), +\fBnamed\fR(8), +\fBnamed.conf\fR(5), +\fBndc\fR(8), +BIND 9 Administrator Reference Manual. +.SH "AUTHOR" +.PP +Internet Systems Consortium +.SH "COPYRIGHT" +Copyright \(co 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") +.br +Copyright \(co 2000, 2001 Internet Software Consortium. +.br diff --git a/contrib/bind-9.5.2/bin/rndc/rndc.c b/contrib/bind-9.5.2/bin/rndc/rndc.c new file mode 100644 index 0000000000..51ed206fb5 --- /dev/null +++ b/contrib/bind-9.5.2/bin/rndc/rndc.c @@ -0,0 +1,859 @@ +/* + * 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 + * 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: rndc.c,v 1.118.128.6 2009/01/19 23:47:01 tbox Exp $ */ + +/*! \file */ + +/* + * Principal Author: DCL + */ + +#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 "util.h" + +#define SERVERADDRS 10 + +const char *progname; +isc_boolean_t verbose; + +static const char *admin_conffile; +static const char *admin_keyfile; +static const char *version = VERSION; +static const char *servername = NULL; +static isc_sockaddr_t serveraddrs[SERVERADDRS]; +static isc_sockaddr_t local4, local6; +static isc_boolean_t local4set = ISC_FALSE, local6set = ISC_FALSE; +static int nserveraddrs; +static int currentaddr = 0; +static unsigned int remoteport = 0; +static isc_socketmgr_t *socketmgr = NULL; +static unsigned char databuf[2048]; +static isccc_ccmsg_t ccmsg; +static isccc_region_t secret; +static isc_boolean_t failed = ISC_FALSE; +static isc_mem_t *mctx; +static int sends, recvs, connects; +static char *command; +static char *args; +static char program[256]; +static isc_socket_t *sock = NULL; +static isc_uint32_t serial; + +static void rndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task); + +static void +usage(int status) { + fprintf(stderr, "\ +Usage: %s [-c config] [-s server] [-p port]\n\ + [-k key-file ] [-y key] [-V] command\n\ +\n\ +command is one of the following:\n\ +\n\ + reload Reload configuration file and zones.\n\ + reload zone [class [view]]\n\ + Reload a single zone.\n\ + refresh zone [class [view]]\n\ + Schedule immediate maintenance for a zone.\n\ + retransfer zone [class [view]]\n\ + Retransfer a single zone without checking serial number.\n\ + freeze Suspend updates to all dynamic zones.\n\ + freeze zone [class [view]]\n\ + Suspend updates to a dynamic zone.\n\ + thaw Enable updates to all dynamic zones and reload them.\n\ + thaw zone [class [view]]\n\ + Enable updates to a frozen dynamic zone and reload it.\n\ + notify zone [class [view]]\n\ + Resend NOTIFY messages for the zone.\n\ + reconfig Reload configuration file and new zones only.\n\ + stats Write server statistics to the statistics file.\n\ + querylog Toggle query logging.\n\ + dumpdb [-all|-cache|-zones] [view ...]\n\ + Dump cache(s) to the dump file (named_dump.db).\n\ + stop Save pending updates to master files and stop the server.\n\ + stop -p Save pending updates to master files and stop the server\n\ + reporting process id.\n\ + halt Stop the server without saving pending updates.\n\ + halt -p Stop the server without saving pending updates reporting\n\ + process id.\n\ + trace Increment debugging level by one.\n\ + trace level Change the debugging level.\n\ + notrace Set debugging level to 0.\n\ + flush Flushes all of the server's caches.\n\ + flush [view] Flushes the server's cache for a view.\n\ + flushname name [view]\n\ + Flush the given name from the server's cache(s)\n\ + status Display status of the server.\n\ + recursing Dump the queries that are currently recursing (named.recursing)\n\ + validation newstate [view]\n\ + Enable / disable DNSSEC validation.\n\ + *restart Restart the server.\n\ +\n\ +* == not yet implemented\n\ +Version: %s\n", + progname, version); + + exit(status); +} + +static void +get_addresses(const char *host, in_port_t port) { + isc_result_t result; + int found = 0, count; + + if (*host == '/') { + result = isc_sockaddr_frompath(&serveraddrs[nserveraddrs], + host); + if (result == ISC_R_SUCCESS) + nserveraddrs++; + } else { + count = SERVERADDRS - nserveraddrs; + result = bind9_getaddresses(host, port, + &serveraddrs[nserveraddrs], + count, &found); + nserveraddrs += found; + } + if (result != ISC_R_SUCCESS) + fatal("couldn't get address for '%s': %s", + host, isc_result_totext(result)); + INSIST(nserveraddrs > 0); +} + +static void +rndc_senddone(isc_task_t *task, isc_event_t *event) { + isc_socketevent_t *sevent = (isc_socketevent_t *)event; + + UNUSED(task); + + sends--; + if (sevent->result != ISC_R_SUCCESS) + fatal("send failed: %s", isc_result_totext(sevent->result)); + isc_event_free(&event); + if (sends == 0 && recvs == 0) { + isc_socket_detach(&sock); + isc_task_shutdown(task); + RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS); + } +} + +static void +rndc_recvdone(isc_task_t *task, isc_event_t *event) { + isccc_sexpr_t *response = NULL; + isccc_sexpr_t *data; + isccc_region_t source; + char *errormsg = NULL; + char *textmsg = NULL; + isc_result_t result; + + recvs--; + + if (ccmsg.result == ISC_R_EOF) + fatal("connection to remote host closed\n" + "This may indicate that\n" + "* the remote server is using an older version of" + " the command protocol,\n" + "* this host is not authorized to connect,\n" + "* the clocks are not synchronized, or\n" + "* the key is invalid."); + + if (ccmsg.result != ISC_R_SUCCESS) + fatal("recv failed: %s", isc_result_totext(ccmsg.result)); + + source.rstart = isc_buffer_base(&ccmsg.buffer); + source.rend = isc_buffer_used(&ccmsg.buffer); + + DO("parse message", isccc_cc_fromwire(&source, &response, &secret)); + + data = isccc_alist_lookup(response, "_data"); + if (data == NULL) + fatal("no data section in response"); + result = isccc_cc_lookupstring(data, "err", &errormsg); + if (result == ISC_R_SUCCESS) { + failed = ISC_TRUE; + fprintf(stderr, "%s: '%s' failed: %s\n", + progname, command, errormsg); + } + else if (result != ISC_R_NOTFOUND) + fprintf(stderr, "%s: parsing response failed: %s\n", + progname, isc_result_totext(result)); + + result = isccc_cc_lookupstring(data, "text", &textmsg); + if (result == ISC_R_SUCCESS) + printf("%s\n", textmsg); + else if (result != ISC_R_NOTFOUND) + fprintf(stderr, "%s: parsing response failed: %s\n", + progname, isc_result_totext(result)); + + isc_event_free(&event); + isccc_sexpr_free(&response); + if (sends == 0 && recvs == 0) { + isc_socket_detach(&sock); + isc_task_shutdown(task); + RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS); + } +} + +static void +rndc_recvnonce(isc_task_t *task, isc_event_t *event) { + isccc_sexpr_t *response = NULL; + isccc_sexpr_t *_ctrl; + isccc_region_t source; + isc_result_t result; + isc_uint32_t nonce; + isccc_sexpr_t *request = NULL; + isccc_time_t now; + isc_region_t r; + isccc_sexpr_t *data; + isccc_region_t message; + isc_uint32_t len; + isc_buffer_t b; + + recvs--; + + if (ccmsg.result == ISC_R_EOF) + fatal("connection to remote host closed\n" + "This may indicate that\n" + "* the remote server is using an older version of" + " the command protocol,\n" + "* this host is not authorized to connect,\n" + "* the clocks are not synchronized, or\n" + "* the key is invalid."); + + if (ccmsg.result != ISC_R_SUCCESS) + fatal("recv failed: %s", isc_result_totext(ccmsg.result)); + + source.rstart = isc_buffer_base(&ccmsg.buffer); + source.rend = isc_buffer_used(&ccmsg.buffer); + + DO("parse message", isccc_cc_fromwire(&source, &response, &secret)); + + _ctrl = isccc_alist_lookup(response, "_ctrl"); + if (_ctrl == NULL) + fatal("_ctrl section missing"); + nonce = 0; + if (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS) + nonce = 0; + + isc_stdtime_get(&now); + + DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial, + now, now + 60, &request)); + data = isccc_alist_lookup(request, "_data"); + if (data == NULL) + fatal("_data section missing"); + if (isccc_cc_definestring(data, "type", args) == NULL) + fatal("out of memory"); + if (nonce != 0) { + _ctrl = isccc_alist_lookup(request, "_ctrl"); + if (_ctrl == NULL) + fatal("_ctrl section missing"); + if (isccc_cc_defineuint32(_ctrl, "_nonce", nonce) == NULL) + fatal("out of memory"); + } + message.rstart = databuf + 4; + message.rend = databuf + sizeof(databuf); + DO("render message", isccc_cc_towire(request, &message, &secret)); + len = sizeof(databuf) - REGION_SIZE(message); + isc_buffer_init(&b, databuf, 4); + isc_buffer_putuint32(&b, len - 4); + r.length = len; + r.base = databuf; + + isccc_ccmsg_cancelread(&ccmsg); + DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task, + rndc_recvdone, NULL)); + recvs++; + DO("send message", isc_socket_send(sock, &r, task, rndc_senddone, + NULL)); + sends++; + + isc_event_free(&event); + isccc_sexpr_free(&response); + return; +} + +static void +rndc_connected(isc_task_t *task, isc_event_t *event) { + char socktext[ISC_SOCKADDR_FORMATSIZE]; + isc_socketevent_t *sevent = (isc_socketevent_t *)event; + isccc_sexpr_t *request = NULL; + isccc_sexpr_t *data; + isccc_time_t now; + isccc_region_t message; + isc_region_t r; + isc_uint32_t len; + isc_buffer_t b; + isc_result_t result; + + connects--; + + if (sevent->result != ISC_R_SUCCESS) { + isc_sockaddr_format(&serveraddrs[currentaddr], socktext, + sizeof(socktext)); + if (sevent->result != ISC_R_CANCELED && + ++currentaddr < nserveraddrs) + { + notify("connection failed: %s: %s", socktext, + isc_result_totext(sevent->result)); + isc_socket_detach(&sock); + isc_event_free(&event); + rndc_startconnect(&serveraddrs[currentaddr], task); + return; + } else + fatal("connect failed: %s: %s", socktext, + isc_result_totext(sevent->result)); + } + + isc_stdtime_get(&now); + DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial, + now, now + 60, &request)); + data = isccc_alist_lookup(request, "_data"); + if (data == NULL) + fatal("_data section missing"); + if (isccc_cc_definestring(data, "type", "null") == NULL) + fatal("out of memory"); + message.rstart = databuf + 4; + message.rend = databuf + sizeof(databuf); + DO("render message", isccc_cc_towire(request, &message, &secret)); + len = sizeof(databuf) - REGION_SIZE(message); + isc_buffer_init(&b, databuf, 4); + isc_buffer_putuint32(&b, len - 4); + r.length = len; + r.base = databuf; + + isccc_ccmsg_init(mctx, sock, &ccmsg); + isccc_ccmsg_setmaxsize(&ccmsg, 1024 * 1024); + + DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task, + rndc_recvnonce, NULL)); + recvs++; + DO("send message", isc_socket_send(sock, &r, task, rndc_senddone, + NULL)); + sends++; + isc_event_free(&event); +} + +static void +rndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task) { + isc_result_t result; + int pf; + isc_sockettype_t type; + + char socktext[ISC_SOCKADDR_FORMATSIZE]; + + isc_sockaddr_format(addr, socktext, sizeof(socktext)); + + notify("using server %s (%s)", servername, socktext); + + pf = isc_sockaddr_pf(addr); + if (pf == AF_INET || pf == AF_INET6) + type = isc_sockettype_tcp; + else + type = isc_sockettype_unix; + DO("create socket", isc_socket_create(socketmgr, pf, type, &sock)); + switch (isc_sockaddr_pf(addr)) { + case AF_INET: + DO("bind socket", isc_socket_bind(sock, &local4, 0)); + break; + case AF_INET6: + DO("bind socket", isc_socket_bind(sock, &local6, 0)); + break; + default: + break; + } + DO("connect", isc_socket_connect(sock, addr, task, rndc_connected, + NULL)); + connects++; +} + +static void +rndc_start(isc_task_t *task, isc_event_t *event) { + isc_event_free(&event); + + currentaddr = 0; + rndc_startconnect(&serveraddrs[currentaddr], task); +} + +static void +parse_config(isc_mem_t *mctx, isc_log_t *log, const char *keyname, + cfg_parser_t **pctxp, cfg_obj_t **configp) +{ + isc_result_t result; + const char *conffile = admin_conffile; + const cfg_obj_t *addresses = NULL; + const cfg_obj_t *defkey = NULL; + const cfg_obj_t *options = NULL; + const cfg_obj_t *servers = NULL; + const cfg_obj_t *server = NULL; + const cfg_obj_t *keys = NULL; + const cfg_obj_t *key = NULL; + const cfg_obj_t *defport = NULL; + const cfg_obj_t *secretobj = NULL; + const cfg_obj_t *algorithmobj = NULL; + cfg_obj_t *config = NULL; + const cfg_obj_t *address = NULL; + const cfg_listelt_t *elt; + const char *secretstr; + const char *algorithm; + static char secretarray[1024]; + const cfg_type_t *conftype = &cfg_type_rndcconf; + isc_boolean_t key_only = ISC_FALSE; + const cfg_listelt_t *element; + + if (! isc_file_exists(conffile)) { + conffile = admin_keyfile; + conftype = &cfg_type_rndckey; + + if (! isc_file_exists(conffile)) + fatal("neither %s nor %s was found", + admin_conffile, admin_keyfile); + key_only = ISC_TRUE; + } + + DO("create parser", cfg_parser_create(mctx, log, pctxp)); + + /* + * The parser will output its own errors, so DO() is not used. + */ + result = cfg_parse_file(*pctxp, conffile, conftype, &config); + if (result != ISC_R_SUCCESS) + fatal("could not load rndc configuration"); + + if (!key_only) + (void)cfg_map_get(config, "options", &options); + + if (key_only && servername == NULL) + servername = "127.0.0.1"; + else if (servername == NULL && options != NULL) { + const cfg_obj_t *defserverobj = NULL; + (void)cfg_map_get(options, "default-server", &defserverobj); + if (defserverobj != NULL) + servername = cfg_obj_asstring(defserverobj); + } + + if (servername == NULL) + fatal("no server specified and no default"); + + if (!key_only) { + (void)cfg_map_get(config, "server", &servers); + if (servers != NULL) { + for (elt = cfg_list_first(servers); + elt != NULL; + elt = cfg_list_next(elt)) + { + const char *name; + server = cfg_listelt_value(elt); + name = cfg_obj_asstring(cfg_map_getname(server)); + if (strcasecmp(name, servername) == 0) + break; + server = NULL; + } + } + } + + /* + * Look for the name of the key to use. + */ + if (keyname != NULL) + ; /* Was set on command line, do nothing. */ + else if (server != NULL) { + DO("get key for server", cfg_map_get(server, "key", &defkey)); + keyname = cfg_obj_asstring(defkey); + } else if (options != NULL) { + DO("get default key", cfg_map_get(options, "default-key", + &defkey)); + keyname = cfg_obj_asstring(defkey); + } else if (!key_only) + fatal("no key for server and no default"); + + /* + * Get the key's definition. + */ + if (key_only) + DO("get key", cfg_map_get(config, "key", &key)); + else { + DO("get config key list", cfg_map_get(config, "key", &keys)); + for (elt = cfg_list_first(keys); + elt != NULL; + elt = cfg_list_next(elt)) + { + key = cfg_listelt_value(elt); + if (strcasecmp(cfg_obj_asstring(cfg_map_getname(key)), + keyname) == 0) + break; + } + if (elt == NULL) + fatal("no key definition for name %s", keyname); + } + (void)cfg_map_get(key, "secret", &secretobj); + (void)cfg_map_get(key, "algorithm", &algorithmobj); + if (secretobj == NULL || algorithmobj == NULL) + fatal("key must have algorithm and secret"); + + secretstr = cfg_obj_asstring(secretobj); + algorithm = cfg_obj_asstring(algorithmobj); + + if (strcasecmp(algorithm, "hmac-md5") != 0) + fatal("unsupported algorithm: %s", algorithm); + + secret.rstart = (unsigned char *)secretarray; + secret.rend = (unsigned char *)secretarray + sizeof(secretarray); + DO("decode base64 secret", isccc_base64_decode(secretstr, &secret)); + secret.rend = secret.rstart; + secret.rstart = (unsigned char *)secretarray; + + /* + * Find the port to connect to. + */ + if (remoteport != 0) + ; /* Was set on command line, do nothing. */ + else { + if (server != NULL) + (void)cfg_map_get(server, "port", &defport); + if (defport == NULL && options != NULL) + (void)cfg_map_get(options, "default-port", &defport); + } + if (defport != NULL) { + remoteport = cfg_obj_asuint32(defport); + if (remoteport > 65535 || remoteport == 0) + fatal("port %u out of range", remoteport); + } else if (remoteport == 0) + remoteport = NS_CONTROL_PORT; + + if (server != NULL) + result = cfg_map_get(server, "addresses", &addresses); + else + result = ISC_R_NOTFOUND; + if (result == ISC_R_SUCCESS) { + for (element = cfg_list_first(addresses); + element != NULL; + element = cfg_list_next(element)) + { + isc_sockaddr_t sa; + + address = cfg_listelt_value(element); + if (!cfg_obj_issockaddr(address)) { + unsigned int myport; + const char *name; + const cfg_obj_t *obj; + + obj = cfg_tuple_get(address, "name"); + name = cfg_obj_asstring(obj); + obj = cfg_tuple_get(address, "port"); + if (cfg_obj_isuint32(obj)) { + myport = cfg_obj_asuint32(obj); + if (myport > ISC_UINT16_MAX || + myport == 0) + fatal("port %u out of range", + myport); + } else + myport = remoteport; + if (nserveraddrs < SERVERADDRS) + get_addresses(name, (in_port_t) myport); + else + fprintf(stderr, "too many address: " + "%s: dropped\n", name); + continue; + } + sa = *cfg_obj_assockaddr(address); + if (isc_sockaddr_getport(&sa) == 0) + isc_sockaddr_setport(&sa, remoteport); + if (nserveraddrs < SERVERADDRS) + serveraddrs[nserveraddrs++] = sa; + else { + char socktext[ISC_SOCKADDR_FORMATSIZE]; + + isc_sockaddr_format(&sa, socktext, + sizeof(socktext)); + fprintf(stderr, + "too many address: %s: dropped\n", + socktext); + } + } + } + + if (!local4set && server != NULL) { + address = NULL; + cfg_map_get(server, "source-address", &address); + if (address != NULL) { + local4 = *cfg_obj_assockaddr(address); + local4set = ISC_TRUE; + } + } + if (!local4set && options != NULL) { + address = NULL; + cfg_map_get(options, "default-source-address", &address); + if (address != NULL) { + local4 = *cfg_obj_assockaddr(address); + local4set = ISC_TRUE; + } + } + + if (!local6set && server != NULL) { + address = NULL; + cfg_map_get(server, "source-address-v6", &address); + if (address != NULL) { + local6 = *cfg_obj_assockaddr(address); + local6set = ISC_TRUE; + } + } + if (!local6set && options != NULL) { + address = NULL; + cfg_map_get(options, "default-source-address-v6", &address); + if (address != NULL) { + local6 = *cfg_obj_assockaddr(address); + local6set = ISC_TRUE; + } + } + + *configp = config; +} + +int +main(int argc, char **argv) { + isc_boolean_t show_final_mem = ISC_FALSE; + isc_result_t result = ISC_R_SUCCESS; + isc_taskmgr_t *taskmgr = NULL; + isc_task_t *task = NULL; + isc_log_t *log = NULL; + isc_logconfig_t *logconfig = NULL; + isc_logdestination_t logdest; + cfg_parser_t *pctx = NULL; + cfg_obj_t *config = NULL; + const char *keyname = NULL; + struct in_addr in; + struct in6_addr in6; + char *p; + size_t argslen; + int ch; + int i; + + result = isc_file_progname(*argv, program, sizeof(program)); + if (result != ISC_R_SUCCESS) + memcpy(program, "rndc", 5); + progname = program; + + admin_conffile = RNDC_CONFFILE; + admin_keyfile = RNDC_KEYFILE; + + isc_sockaddr_any(&local4); + isc_sockaddr_any6(&local6); + + result = isc_app_start(); + if (result != ISC_R_SUCCESS) + fatal("isc_app_start() failed: %s", isc_result_totext(result)); + + isc_commandline_errprint = ISC_FALSE; + + while ((ch = isc_commandline_parse(argc, argv, "b:c:hk:Mmp:s:Vy:")) + != -1) { + switch (ch) { + case 'b': + if (inet_pton(AF_INET, isc_commandline_argument, + &in) == 1) { + isc_sockaddr_fromin(&local4, &in, 0); + local4set = ISC_TRUE; + } else if (inet_pton(AF_INET6, isc_commandline_argument, + &in6) == 1) { + isc_sockaddr_fromin6(&local6, &in6, 0); + local6set = ISC_TRUE; + } + break; + + case 'c': + admin_conffile = isc_commandline_argument; + break; + + case 'k': + admin_keyfile = isc_commandline_argument; + break; + + case 'M': + isc_mem_debugging = ISC_MEM_DEBUGTRACE; + break; + + case 'm': + show_final_mem = ISC_TRUE; + break; + + case 'p': + remoteport = atoi(isc_commandline_argument); + if (remoteport > 65535 || remoteport == 0) + fatal("port '%s' out of range", + isc_commandline_argument); + break; + + case 's': + servername = isc_commandline_argument; + break; + + case 'V': + verbose = ISC_TRUE; + break; + + case 'y': + keyname = isc_commandline_argument; + break; + + case '?': + if (isc_commandline_option != '?') { + fprintf(stderr, "%s: invalid argument -%c\n", + program, isc_commandline_option); + usage(1); + } + case 'h': + usage(0); + break; + default: + fprintf(stderr, "%s: unhandled option -%c\n", + program, isc_commandline_option); + exit(1); + } + } + + argc -= isc_commandline_index; + argv += isc_commandline_index; + + if (argc < 1) + usage(1); + + isc_random_get(&serial); + + DO("create memory context", isc_mem_create(0, 0, &mctx)); + DO("create socket manager", isc_socketmgr_create(mctx, &socketmgr)); + DO("create task manager", isc_taskmgr_create(mctx, 1, 0, &taskmgr)); + DO("create task", isc_task_create(taskmgr, 0, &task)); + + DO("create logging context", isc_log_create(mctx, &log, &logconfig)); + isc_log_setcontext(log); + DO("setting log tag", isc_log_settag(logconfig, progname)); + logdest.file.stream = stderr; + logdest.file.name = NULL; + logdest.file.versions = ISC_LOG_ROLLNEVER; + logdest.file.maximum_size = 0; + DO("creating log channel", + isc_log_createchannel(logconfig, "stderr", + ISC_LOG_TOFILEDESC, ISC_LOG_INFO, &logdest, + ISC_LOG_PRINTTAG|ISC_LOG_PRINTLEVEL)); + DO("enabling log channel", isc_log_usechannel(logconfig, "stderr", + NULL, NULL)); + + parse_config(mctx, log, keyname, &pctx, &config); + + isccc_result_register(); + + command = *argv; + + /* + * Convert argc/argv into a space-delimited command string + * similar to what the user might enter in interactive mode + * (if that were implemented). + */ + argslen = 0; + for (i = 0; i < argc; i++) + argslen += strlen(argv[i]) + 1; + + args = isc_mem_get(mctx, argslen); + if (args == NULL) + DO("isc_mem_get", ISC_R_NOMEMORY); + + p = args; + for (i = 0; i < argc; i++) { + size_t len = strlen(argv[i]); + memcpy(p, argv[i], len); + p += len; + *p++ = ' '; + } + + p--; + *p++ = '\0'; + INSIST(p == args + argslen); + + notify("%s", command); + + if (strcmp(command, "restart") == 0) + fatal("'%s' is not implemented", command); + + if (nserveraddrs == 0) + get_addresses(servername, (in_port_t) remoteport); + + DO("post event", isc_app_onrun(mctx, task, rndc_start, NULL)); + + result = isc_app_run(); + if (result != ISC_R_SUCCESS) + fatal("isc_app_run() failed: %s", isc_result_totext(result)); + + if (connects > 0 || sends > 0 || recvs > 0) + isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL); + + isc_task_detach(&task); + isc_taskmgr_destroy(&taskmgr); + isc_socketmgr_destroy(&socketmgr); + isc_log_destroy(&log); + isc_log_setcontext(NULL); + + cfg_obj_destroy(pctx, &config); + cfg_parser_destroy(&pctx); + + isc_mem_put(mctx, args, argslen); + isccc_ccmsg_invalidate(&ccmsg); + + dns_name_destroy(); + + if (show_final_mem) + isc_mem_stats(mctx, stderr); + + isc_mem_destroy(&mctx); + + if (failed) + return (1); + + return (0); +} diff --git a/contrib/bind-9.5.2/bin/rndc/rndc.conf b/contrib/bind-9.5.2/bin/rndc/rndc.conf new file mode 100644 index 0000000000..67542b91c7 --- /dev/null +++ b/contrib/bind-9.5.2/bin/rndc/rndc.conf @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * 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: rndc.conf,v 1.11 2007/06/19 23:46:59 tbox Exp $ */ + +/* + * Sample rndc configuration file. + */ + +options { + default-server localhost; + default-key "key"; +}; + +server localhost { + key "key"; +}; + +key "cc64b3d1db63fc88d7cb5d2f9f57d258" { + algorithm hmac-md5; + secret "34f88008d07deabbe65bd01f1d233d47"; +}; + +server "test1" { + key "cc64b3d1db63fc88d7cb5d2f9f57d258"; + port 5353; + addresses { 10.53.0.1; }; +}; + +key "key" { + algorithm hmac-md5; + secret "c3Ryb25nIGVub3VnaCBmb3IgYSBtYW4gYnV0IG1hZGUgZm9yIGEgd29tYW4K"; +}; diff --git a/contrib/bind-9.5.2/bin/rndc/rndc.conf.5 b/contrib/bind-9.5.2/bin/rndc/rndc.conf.5 new file mode 100644 index 0000000000..9265664038 --- /dev/null +++ b/contrib/bind-9.5.2/bin/rndc/rndc.conf.5 @@ -0,0 +1,214 @@ +.\" Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2000, 2001 Internet Software Consortium. +.\" +.\" 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: rndc.conf.5,v 1.38.162.1 2009/07/11 01:43:30 tbox Exp $ +.\" +.hy 0 +.ad l +.\" Title: \fIrndc.conf\fR +.\" Author: +.\" Generator: DocBook XSL Stylesheets v1.71.1 +.\" Date: June 30, 2000 +.\" Manual: BIND9 +.\" Source: BIND9 +.\" +.TH "\fIRNDC.CONF\fR" "5" "June 30, 2000" "BIND9" "BIND9" +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.SH "NAME" +rndc.conf \- rndc configuration file +.SH "SYNOPSIS" +.HP 10 +\fBrndc.conf\fR +.SH "DESCRIPTION" +.PP +\fIrndc.conf\fR +is the configuration file for +\fBrndc\fR, the BIND 9 name server control utility. This file has a similar structure and syntax to +\fInamed.conf\fR. Statements are enclosed in braces and terminated with a semi\-colon. Clauses in the statements are also semi\-colon terminated. The usual comment styles are supported: +.PP +C style: /* */ +.PP +C++ style: // to end of line +.PP +Unix style: # to end of line +.PP +\fIrndc.conf\fR +is much simpler than +\fInamed.conf\fR. The file uses three statements: an options statement, a server statement and a key statement. +.PP +The +\fBoptions\fR +statement contains five clauses. The +\fBdefault\-server\fR +clause is followed by the name or address of a name server. This host will be used when no name server is given as an argument to +\fBrndc\fR. The +\fBdefault\-key\fR +clause is followed by the name of a key which is identified by a +\fBkey\fR +statement. If no +\fBkeyid\fR +is provided on the rndc command line, and no +\fBkey\fR +clause is found in a matching +\fBserver\fR +statement, this default key will be used to authenticate the server's commands and responses. The +\fBdefault\-port\fR +clause is followed by the port to connect to on the remote name server. If no +\fBport\fR +option is provided on the rndc command line, and no +\fBport\fR +clause is found in a matching +\fBserver\fR +statement, this default port will be used to connect. The +\fBdefault\-source\-address\fR +and +\fBdefault\-source\-address\-v6\fR +clauses which can be used to set the IPv4 and IPv6 source addresses respectively. +.PP +After the +\fBserver\fR +keyword, the server statement includes a string which is the hostname or address for a name server. The statement has three possible clauses: +\fBkey\fR, +\fBport\fR +and +\fBaddresses\fR. The key name must match the name of a key statement in the file. The port number specifies the port to connect to. If an +\fBaddresses\fR +clause is supplied these addresses will be used instead of the server name. Each address can take an optional port. If an +\fBsource\-address\fR +or +\fBsource\-address\-v6\fR +of supplied then these will be used to specify the IPv4 and IPv6 source addresses respectively. +.PP +The +\fBkey\fR +statement begins with an identifying string, the name of the key. The statement has two clauses. +\fBalgorithm\fR +identifies the encryption algorithm for +\fBrndc\fR +to use; currently only HMAC\-MD5 is supported. This is followed by a secret clause which contains the base\-64 encoding of the algorithm's encryption key. The base\-64 string is enclosed in double quotes. +.PP +There are two common ways to generate the base\-64 string for the secret. The BIND 9 program +\fBrndc\-confgen\fR +can be used to generate a random key, or the +\fBmmencode\fR +program, also known as +\fBmimencode\fR, can be used to generate a base\-64 string from known input. +\fBmmencode\fR +does not ship with BIND 9 but is available on many systems. See the EXAMPLE section for sample command lines for each. +.SH "EXAMPLE" +.PP +.RS 4 +.nf + options { + default\-server localhost; + default\-key samplekey; + }; +.fi +.RE +.sp +.PP +.RS 4 +.nf + server localhost { + key samplekey; + }; +.fi +.RE +.sp +.PP +.RS 4 +.nf + server testserver { + key testkey; + addresses { localhost port 5353; }; + }; +.fi +.RE +.sp +.PP +.RS 4 +.nf + key samplekey { + algorithm hmac\-md5; + secret "6FMfj43Osz4lyb24OIe2iGEz9lf1llJO+lz"; + }; +.fi +.RE +.sp +.PP +.RS 4 +.nf + key testkey { + algorithm hmac\-md5; + secret "R3HI8P6BKw9ZwXwN3VZKuQ=="; + }; +.fi +.RE +.sp +.PP +In the above example, +\fBrndc\fR +will by default use the server at localhost (127.0.0.1) and the key called samplekey. Commands to the localhost server will use the samplekey key, which must also be defined in the server's configuration file with the same name and secret. The key statement indicates that samplekey uses the HMAC\-MD5 algorithm and its secret clause contains the base\-64 encoding of the HMAC\-MD5 secret enclosed in double quotes. +.PP +If +\fBrndc \-s testserver\fR +is used then +\fBrndc\fR +will connect to server on localhost port 5353 using the key testkey. +.PP +To generate a random secret with +\fBrndc\-confgen\fR: +.PP +\fBrndc\-confgen\fR +.PP +A complete +\fIrndc.conf\fR +file, including the randomly generated key, will be written to the standard output. Commented\-out +\fBkey\fR +and +\fBcontrols\fR +statements for +\fInamed.conf\fR +are also printed. +.PP +To generate a base\-64 secret with +\fBmmencode\fR: +.PP +\fBecho "known plaintext for a secret" | mmencode\fR +.SH "NAME SERVER CONFIGURATION" +.PP +The name server must be configured to accept rndc connections and to recognize the key specified in the +\fIrndc.conf\fR +file, using the controls statement in +\fInamed.conf\fR. See the sections on the +\fBcontrols\fR +statement in the BIND 9 Administrator Reference Manual for details. +.SH "SEE ALSO" +.PP +\fBrndc\fR(8), +\fBrndc\-confgen\fR(8), +\fBmmencode\fR(1), +BIND 9 Administrator Reference Manual. +.SH "AUTHOR" +.PP +Internet Systems Consortium +.SH "COPYRIGHT" +Copyright \(co 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") +.br +Copyright \(co 2000, 2001 Internet Software Consortium. +.br diff --git a/contrib/bind-9.5.2/bin/rndc/rndc.conf.html b/contrib/bind-9.5.2/bin/rndc/rndc.conf.html new file mode 100644 index 0000000000..367bd5cd50 --- /dev/null +++ b/contrib/bind-9.5.2/bin/rndc/rndc.conf.html @@ -0,0 +1,217 @@ + + + + + +rndc.conf + + +
+
+
+

Name

+

rndc.conf — rndc configuration file

+
+
+

Synopsis

+

rndc.conf

+
+
+

DESCRIPTION

+

rndc.conf is the configuration file + for rndc, the BIND 9 name server control + utility. This file has a similar structure and syntax to + named.conf. Statements are enclosed + in braces and terminated with a semi-colon. Clauses in + the statements are also semi-colon terminated. The usual + comment styles are supported: +

+

+ C style: /* */ +

+

+ C++ style: // to end of line +

+

+ Unix style: # to end of line +

+

rndc.conf is much simpler than + named.conf. The file uses three + statements: an options statement, a server statement + and a key statement. +

+

+ The options statement contains five clauses. + The default-server clause is followed by the + name or address of a name server. This host will be used when + no name server is given as an argument to + rndc. The default-key + clause is followed by the name of a key which is identified by + a key statement. If no + keyid is provided on the rndc command line, + and no key clause is found in a matching + server statement, this default key will be + used to authenticate the server's commands and responses. The + default-port clause is followed by the port + to connect to on the remote name server. If no + port option is provided on the rndc command + line, and no port clause is found in a + matching server statement, this default port + will be used to connect. + The default-source-address and + default-source-address-v6 clauses which + can be used to set the IPv4 and IPv6 source addresses + respectively. +

+

+ After the server keyword, the server + statement includes a string which is the hostname or address + for a name server. The statement has three possible clauses: + key, port and + addresses. The key name must match the + name of a key statement in the file. The port number + specifies the port to connect to. If an addresses + clause is supplied these addresses will be used instead of + the server name. Each address can take an optional port. + If an source-address or source-address-v6 + of supplied then these will be used to specify the IPv4 and IPv6 + source addresses respectively. +

+

+ The key statement begins with an identifying + string, the name of the key. The statement has two clauses. + algorithm identifies the encryption algorithm + for rndc to use; currently only HMAC-MD5 + is + supported. This is followed by a secret clause which contains + the base-64 encoding of the algorithm's encryption key. The + base-64 string is enclosed in double quotes. +

+

+ There are two common ways to generate the base-64 string for the + secret. The BIND 9 program rndc-confgen + can + be used to generate a random key, or the + mmencode program, also known as + mimencode, can be used to generate a + base-64 + string from known input. mmencode does + not + ship with BIND 9 but is available on many systems. See the + EXAMPLE section for sample command lines for each. +

+
+
+

EXAMPLE

+
+      options {
+        default-server  localhost;
+        default-key     samplekey;
+      };
+
+

+

+
+      server localhost {
+        key             samplekey;
+      };
+
+

+

+
+      server testserver {
+        key		testkey;
+        addresses	{ localhost port 5353; };
+      };
+
+

+

+
+      key samplekey {
+        algorithm       hmac-md5;
+        secret          "6FMfj43Osz4lyb24OIe2iGEz9lf1llJO+lz";
+      };
+
+

+

+
+      key testkey {
+        algorithm	hmac-md5;
+        secret		"R3HI8P6BKw9ZwXwN3VZKuQ==";
+      };
+    
+

+

+

+ In the above example, rndc will by + default use + the server at localhost (127.0.0.1) and the key called samplekey. + Commands to the localhost server will use the samplekey key, which + must also be defined in the server's configuration file with the + same name and secret. The key statement indicates that samplekey + uses the HMAC-MD5 algorithm and its secret clause contains the + base-64 encoding of the HMAC-MD5 secret enclosed in double quotes. +

+

+ If rndc -s testserver is used then rndc will + connect to server on localhost port 5353 using the key testkey. +

+

+ To generate a random secret with rndc-confgen: +

+

rndc-confgen +

+

+ A complete rndc.conf file, including + the + randomly generated key, will be written to the standard + output. Commented-out key and + controls statements for + named.conf are also printed. +

+

+ To generate a base-64 secret with mmencode: +

+

echo "known plaintext for a secret" | mmencode +

+
+
+

NAME SERVER CONFIGURATION

+

+ The name server must be configured to accept rndc connections and + to recognize the key specified in the rndc.conf + file, using the controls statement in named.conf. + See the sections on the controls statement in the + BIND 9 Administrator Reference Manual for details. +

+
+
+

SEE ALSO

+

rndc(8), + rndc-confgen(8), + mmencode(1), + BIND 9 Administrator Reference Manual. +

+
+
+

AUTHOR

+

Internet Systems Consortium +

+
+
+ diff --git a/contrib/bind-9.5.2/bin/rndc/rndc.html b/contrib/bind-9.5.2/bin/rndc/rndc.html new file mode 100644 index 0000000000..2aacf741df --- /dev/null +++ b/contrib/bind-9.5.2/bin/rndc/rndc.html @@ -0,0 +1,165 @@ + + + + + +rndc + + +
+
+
+

Name

+

rndc — name server control utility

+
+
+

Synopsis

+

rndc [-b source-address] [-c config-file] [-k key-file] [-s server] [-p port] [-V] [-y key_id] {command}

+
+
+

DESCRIPTION

+

rndc + controls the operation of a name + server. It supersedes the ndc utility + that was provided in old BIND releases. If + rndc is invoked with no command line + options or arguments, it prints a short summary of the + supported commands and the available options and their + arguments. +

+

rndc + communicates with the name server + over a TCP connection, sending commands authenticated with + digital signatures. In the current versions of + rndc and named, + the only supported authentication algorithm is HMAC-MD5, + which uses a shared secret on each end of the connection. + This provides TSIG-style authentication for the command + request and the name server's response. All commands sent + over the channel must be signed by a key_id known to the + server. +

+

rndc + reads a configuration file to + determine how to contact the name server and decide what + algorithm and key it should use. +

+
+
+

OPTIONS

+
+
-b source-address
+

+ Use source-address + as the source address for the connection to the server. + Multiple instances are permitted to allow setting of both + the IPv4 and IPv6 source addresses. +

+
-c config-file
+

+ Use config-file + as the configuration file instead of the default, + /etc/rndc.conf. +

+
-k key-file
+

+ Use key-file + as the key file instead of the default, + /etc/rndc.key. The key in + /etc/rndc.key will be used to + authenticate + commands sent to the server if the config-file + does not exist. +

+
-s server
+

server is + the name or address of the server which matches a + server statement in the configuration file for + rndc. If no server is supplied on the + command line, the host named by the default-server clause + in the options statement of the rndc + configuration file will be used. +

+
-p port
+

+ Send commands to TCP port + port + instead + of BIND 9's default control channel port, 953. +

+
-V
+

+ Enable verbose logging. +

+
-y key_id
+

+ Use the key key_id + from the configuration file. + key_id + must be + known by named with the same algorithm and secret string + in order for control message validation to succeed. + If no key_id + is specified, rndc will first look + for a key clause in the server statement of the server + being used, or if no server statement is present for that + host, then the default-key clause of the options statement. + Note that the configuration file contains shared secrets + which are used to send authenticated control commands + to name servers. It should therefore not have general read + or write access. +

+
+

+ For the complete set of commands supported by rndc, + see the BIND 9 Administrator Reference Manual or run + rndc without arguments to see its help + message. +

+
+
+

LIMITATIONS

+

rndc + does not yet support all the commands of + the BIND 8 ndc utility. +

+

+ There is currently no way to provide the shared secret for a + key_id without using the configuration file. +

+

+ Several error messages could be clearer. +

+
+
+

SEE ALSO

+

rndc.conf(5), + rndc-confgen(8), + named(8), + named.conf(5), + ndc(8), + BIND 9 Administrator Reference Manual. +

+
+
+

AUTHOR

+

Internet Systems Consortium +

+
+
+ diff --git a/contrib/bind-9.5.2/bin/rndc/unix/os.c b/contrib/bind-9.5.2/bin/rndc/unix/os.c new file mode 100644 index 0000000000..ddf8259838 --- /dev/null +++ b/contrib/bind-9.5.2/bin/rndc/unix/os.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001 Internet Software Consortium. + * + * 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: os.c,v 1.10 2007/06/19 23:46:59 tbox Exp $ */ + +/*! \file */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +int +set_user(FILE *fd, const char *user) { + struct passwd *pw; + + pw = getpwnam(user); + if (pw == NULL) { + errno = EINVAL; + return (-1); + } + return (fchown(fileno(fd), pw->pw_uid, -1)); +} + +FILE * +safe_create(const char *filename) { + int fd; + FILE *f; + struct stat sb; + int flags = O_WRONLY; + + if (stat(filename, &sb) == -1) { + if (errno != ENOENT) + return (NULL); + flags = O_WRONLY | O_CREAT | O_EXCL; + } else if ((sb.st_mode & S_IFREG) == 0) { + errno = EOPNOTSUPP; + return (NULL); + } else + flags = O_WRONLY | O_TRUNC; + + fd = open(filename, flags, S_IRUSR | S_IWUSR); + if (fd == -1) + return (NULL); + f = fdopen(fd, "w"); + if (f == NULL) + close(fd); + return (f); +} diff --git a/contrib/bind-9.5.2/bin/rndc/util.c b/contrib/bind-9.5.2/bin/rndc/util.c new file mode 100644 index 0000000000..c654462bf0 --- /dev/null +++ b/contrib/bind-9.5.2/bin/rndc/util.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * 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: util.c,v 1.7 2007/06/19 23:46:59 tbox Exp $ */ + +/*! \file */ + +#include + +#include +#include +#include + +#include + +#include "util.h" + +extern isc_boolean_t verbose; +extern const char *progname; + +void +notify(const char *fmt, ...) { + va_list ap; + + if (verbose) { + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fputs("\n", stderr); + } +} + +void +fatal(const char *format, ...) { + va_list args; + + fprintf(stderr, "%s: ", progname); + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + exit(1); +} diff --git a/contrib/bind-9.5.2/bin/rndc/util.h b/contrib/bind-9.5.2/bin/rndc/util.h new file mode 100644 index 0000000000..7adcaa5bfa --- /dev/null +++ b/contrib/bind-9.5.2/bin/rndc/util.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * 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: util.h,v 1.10 2007/06/19 23:46:59 tbox Exp $ */ + +#ifndef RNDC_UTIL_H +#define RNDC_UTIL_H 1 + +/*! \file */ + +#include + +#include + +#define NS_CONTROL_PORT 953 + +#undef DO +#define DO(name, function) \ + do { \ + result = function; \ + if (result != ISC_R_SUCCESS) \ + fatal("%s: %s", name, isc_result_totext(result)); \ + else \ + notify("%s", name); \ + } while (0) + +ISC_LANG_BEGINDECLS + +void +notify(const char *fmt, ...) ISC_FORMAT_PRINTF(1, 2); + +void +fatal(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +ISC_LANG_ENDDECLS + +#endif /* RNDC_UTIL_H */ diff --git a/contrib/bind-9.5.2/bind.keys b/contrib/bind-9.5.2/bind.keys new file mode 100644 index 0000000000..49e0a97e96 --- /dev/null +++ b/contrib/bind-9.5.2/bind.keys @@ -0,0 +1,6 @@ +trusted-keys { + # NOTE: This key is current as of September 2009. + # If it doesn't work, it may have expired; see + # https://www.isc.org/solutions/dlv for a replacement + dlv.isc.org. 257 3 5 "BEAAAAPHMu/5onzrEE7z1egmhg/WPO0+juoZrW3euWEn4MxDCE1+lLy2 brhQv5rN32RKtMzX6Mj70jdzeND4XknW58dnJNPCxn8+jAGl2FZLK8t+ 1uq4W+nnA3qO2+DL+k6BD4mewMLbIYFwe0PG73Te9fZ2kJb56dhgMde5 ymX4BI/oQ+cAK50/xvJv00Frf8kw6ucMTwFlgPe+jnGxPPEmHAte/URk Y62ZfkLoBAADLHQ9IrS2tryAe7mbBZVcOwIeU/Rw/mRx/vwwMCTgNboM QKtUdvNXDrYJDSHZws3xiRXF1Rf+al9UmZfSav/4NWLKjHzpT59k/VSt TDN0YUuWrBNh"; +}; diff --git a/contrib/bind-9.5.2/lib/bind/README b/contrib/bind-9.5.2/lib/bind/README new file mode 100644 index 0000000000..b89cff7095 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/README @@ -0,0 +1,4 @@ +--with-irs-gr=yes #define WANT_IRS_GR +--with-irs-nis=yes #define WANT_IRS_NIS +--with-irs-pw=yes #define WANT_IRS_PW + diff --git a/contrib/bind-9.5.2/lib/bind/api b/contrib/bind-9.5.2/lib/bind/api new file mode 100644 index 0000000000..7ffeba810f --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/api @@ -0,0 +1,3 @@ +LIBINTERFACE = 5 +LIBREVISION = 2 +LIBAGE = 1 diff --git a/contrib/bind-9.5.2/lib/bind/bsd/daemon.c b/contrib/bind-9.5.2/lib/bind/bsd/daemon.c new file mode 100644 index 0000000000..54ff83b753 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/bsd/daemon.c @@ -0,0 +1,81 @@ +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)daemon.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: daemon.c,v 1.2 2005/04/27 04:56:10 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "port_before.h" + +#include +#include +#include + +#include "port_after.h" + +#ifndef NEED_DAEMON +int __bind_daemon__; +#else + +int +daemon(int nochdir, int noclose) { + int fd; + + switch (fork()) { + case -1: + return (-1); + case 0: + break; + default: + _exit(0); + } + + if (setsid() == -1) + return (-1); + + if (!nochdir) + (void)chdir("/"); + + if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { + (void)dup2(fd, STDIN_FILENO); + (void)dup2(fd, STDOUT_FILENO); + (void)dup2(fd, STDERR_FILENO); + if (fd > 2) + (void)close (fd); + } + return (0); +} +#endif + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/bsd/ftruncate.c b/contrib/bind-9.5.2/lib/bind/bsd/ftruncate.c new file mode 100644 index 0000000000..5ac4ebac9b --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/bsd/ftruncate.c @@ -0,0 +1,64 @@ +#ifndef LINT +static const char rcsid[] = "$Id: ftruncate.c,v 1.3 2005/04/27 18:16:45 sra Exp $"; +#endif + +/*! \file + * \brief + * ftruncate - set file size, BSD Style + * + * shortens or enlarges the file as neeeded + * uses some undocumented locking call. It is known to work on SCO unix, + * other vendors should try. + * The #error directive prevents unsupported OSes + */ + +#include "port_before.h" + +#if defined(M_UNIX) +#define OWN_FTRUNCATE +#include +#ifdef _XOPEN_SOURCE +#undef _XOPEN_SOURCE +#endif +#ifdef _POSIX_SOURCE +#undef _POSIX_SOURCE +#endif + +#include + +#include "port_after.h" + +int +__ftruncate(int fd, long wantsize) { + long cursize; + + /* determine current file size */ + if ((cursize = lseek(fd, 0L, 2)) == -1) + return (-1); + + /* maybe lengthen... */ + if (cursize < wantsize) { + if (lseek(fd, wantsize - 1, 0) == -1 || + write(fd, "", 1) == -1) { + return (-1); + } + return (0); + } + + /* maybe shorten... */ + if (wantsize < cursize) { + struct flock fl; + + fl.l_whence = 0; + fl.l_len = 0; + fl.l_start = wantsize; + fl.l_type = F_WRLCK; + return (fcntl(fd, F_FREESP, &fl)); + } + return (0); +} +#endif + +#ifndef OWN_FTRUNCATE +int __bindcompat_ftruncate; +#endif diff --git a/contrib/bind-9.5.2/lib/bind/bsd/gettimeofday.c b/contrib/bind-9.5.2/lib/bind/bsd/gettimeofday.c new file mode 100644 index 0000000000..75b69430f6 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/bsd/gettimeofday.c @@ -0,0 +1,64 @@ +#ifndef LINT +static const char rcsid[] = "$Id: gettimeofday.c,v 1.4 2005/04/27 04:56:11 sra Exp $"; +#endif + +#include "port_before.h" +#include +#include +#include +#include "port_after.h" + +#if !defined(NEED_GETTIMEOFDAY) +/*% + * gettimeofday() occasionally returns invalid tv_usec on some platforms. + */ +#define MILLION 1000000 +#undef gettimeofday + +int +isc__gettimeofday(struct timeval *tp, struct timezone *tzp) { + int res; + + res = gettimeofday(tp, tzp); + if (res < 0) + return (res); + if (tp == NULL) + return (res); + if (tp->tv_usec < 0) { + do { + tp->tv_usec += MILLION; + tp->tv_sec--; + } while (tp->tv_usec < 0); + goto log; + } else if (tp->tv_usec > MILLION) { + do { + tp->tv_usec -= MILLION; + tp->tv_sec++; + } while (tp->tv_usec > MILLION); + goto log; + } + return (res); + log: + syslog(LOG_ERR, "gettimeofday: tv_usec out of range\n"); + return (res); +} +#else +int +gettimeofday(struct timeval *tvp, struct _TIMEZONE *tzp) { + time_t clock, time(time_t *); + + if (time(&clock) == (time_t) -1) + return (-1); + if (tvp) { + tvp->tv_sec = clock; + tvp->tv_usec = 0; + } + if (tzp) { + tzp->tz_minuteswest = 0; + tzp->tz_dsttime = 0; + } + return (0); +} +#endif /*NEED_GETTIMEOFDAY*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/bsd/mktemp.c b/contrib/bind-9.5.2/lib/bind/bsd/mktemp.c new file mode 100644 index 0000000000..001b24b58f --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/bsd/mktemp.c @@ -0,0 +1,156 @@ +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: mktemp.c,v 1.2 2005/04/27 04:56:11 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Copyright (c) 1987, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#include "port_before.h" + +#include +#include + +#include +#include +#include +#include + +#include "port_after.h" + +#if (!defined(NEED_MKTEMP)) && (!defined(NEED_MKSTEMP)) +int __mktemp_unneeded__; +#else + +static int gettemp(char *path, int *doopen); + +#ifdef NEED_MKSTEMP +mkstemp(char *path) { + int fd; + + return (gettemp(path, &fd) ? fd : -1); +} +#endif + +#ifdef NEED_MKTEMP +char * +mktemp(char *path) { + return(gettemp(path, (int *)NULL) ? path : (char *)NULL); +} +#endif + +static int +gettemp(char *path, int *doopen) { + char *start, *trv; + struct stat sbuf; + u_int pid; + + pid = getpid(); + for (trv = path; *trv; ++trv); /*%< extra X's get set to 0's */ + while (*--trv == 'X') { + *trv = (pid % 10) + '0'; + pid /= 10; + } + + /* + * check the target directory; if you have six X's and it + * doesn't exist this runs for a *very* long time. + */ + for (start = trv + 1;; --trv) { + if (trv <= path) + break; + if (*trv == '/') { + *trv = '\0'; + if (stat(path, &sbuf)) + return(0); + if (!S_ISDIR(sbuf.st_mode)) { + errno = ENOTDIR; + return(0); + } + *trv = '/'; + break; + } + } + + for (;;) { + if (doopen) { + if ((*doopen = + open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0) + return(1); + if (errno != EEXIST) + return(0); + } + else if (stat(path, &sbuf)) + return(errno == ENOENT ? 1 : 0); + + /* tricky little algorithm for backward compatibility */ + for (trv = start;;) { + if (!*trv) + return(0); + if (*trv == 'z') + *trv++ = 'a'; + else { + if (isdigit(*trv)) + *trv = 'a'; + else + ++*trv; + break; + } + } + } + /*NOTREACHED*/ +} + +#endif /*NEED_MKTEMP*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/bsd/putenv.c b/contrib/bind-9.5.2/lib/bind/bsd/putenv.c new file mode 100644 index 0000000000..2dcbc57e6c --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/bsd/putenv.c @@ -0,0 +1,27 @@ +#ifndef LINT +static const char rcsid[] = "$Id: putenv.c,v 1.2 2005/04/27 04:56:11 sra Exp $"; +#endif + +#include "port_before.h" +#include "port_after.h" + +/*% + * To give a little credit to Sun, SGI, + * and many vendors in the SysV world. + */ + +#if !defined(NEED_PUTENV) +int __bindcompat_putenv; +#else +int +putenv(char *str) { + char *tmp; + + for (tmp = str; *tmp && (*tmp != '='); tmp++) + ; + + return (setenv(str, tmp, 1)); +} +#endif + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/bsd/readv.c b/contrib/bind-9.5.2/lib/bind/bsd/readv.c new file mode 100644 index 0000000000..5fa691a92f --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/bsd/readv.c @@ -0,0 +1,39 @@ +#ifndef LINT +static const char rcsid[] = "$Id: readv.c,v 1.2 2005/04/27 04:56:11 sra Exp $"; +#endif + +#include "port_before.h" + +#include +#include +#include +#include + +#include "port_after.h" + +#ifndef NEED_READV +int __bindcompat_readv; +#else + +int +__readv(fd, vp, vpcount) + int fd; + const struct iovec *vp; + int vpcount; +{ + int count = 0; + + while (vpcount-- > 0) { + int bytes = read(fd, vp->iov_base, vp->iov_len); + + if (bytes < 0) + return (-1); + count += bytes; + if (bytes != vp->iov_len) + break; + vp++; + } + return (count); +} +#endif /* NEED_READV */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/bsd/setenv.c b/contrib/bind-9.5.2/lib/bind/bsd/setenv.c new file mode 100644 index 0000000000..baf00f6ff2 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/bsd/setenv.c @@ -0,0 +1,151 @@ +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)setenv.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: setenv.c,v 1.2 2005/04/27 04:56:11 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Copyright (c) 1987, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "port_before.h" + +#include +#include +#include + +#include "port_after.h" + +#if !defined(NEED_SETENV) +int __bindcompat_setenv; +#else + +extern char **environ; + +static char *findenv(const char *name, int *offset); + +/*% + * setenv -- + * Set the value of the environmental variable "name" to be + * "value". If rewrite is set, replace any current value. + */ +setenv(const char *name, const char *value, int rewrite) { + extern char **environ; + static int alloced; /*%< if allocated space before */ + char *c; + int l_value, offset; + + if (*value == '=') /*%< no `=' in value */ + ++value; + l_value = strlen(value); + if ((c = findenv(name, &offset))) { /*%< find if already exists */ + if (!rewrite) + return (0); + if (strlen(c) >= l_value) { /*%< old larger; copy over */ + while (*c++ = *value++); + return (0); + } + } else { /*%< create new slot */ + int cnt; + char **p; + + for (p = environ, cnt = 0; *p; ++p, ++cnt); + if (alloced) { /*%< just increase size */ + environ = (char **)realloc((char *)environ, + (size_t)(sizeof(char *) * (cnt + 2))); + if (!environ) + return (-1); + } + else { /*%< get new space */ + alloced = 1; /*%< copy old entries into it */ + p = malloc((size_t)(sizeof(char *) * (cnt + 2))); + if (!p) + return (-1); + memcpy(p, environ, cnt * sizeof(char *)); + environ = p; + } + environ[cnt + 1] = NULL; + offset = cnt; + } + for (c = (char *)name; *c && *c != '='; ++c); /*%< no `=' in name */ + if (!(environ[offset] = /*%< name + `=' + value */ + malloc((size_t)((int)(c - name) + l_value + 2)))) + return (-1); + for (c = environ[offset]; (*c = *name++) && *c != '='; ++c); + for (*c++ = '='; *c++ = *value++;); + return (0); +} + +/*% + * unsetenv(name) -- + * Delete environmental variable "name". + */ +void +unsetenv(const char *name) { + char **p; + int offset; + + while (findenv(name, &offset)) /*%< if set multiple times */ + for (p = &environ[offset];; ++p) + if (!(*p = *(p + 1))) + break; +} + +/*% + * findenv -- + * Returns pointer to value associated with name, if any, else NULL. + * Sets offset to be the offset of the name/value combination in the + * environmental array, for use by setenv(3) and unsetenv(3). + * Explicitly removes '=' in argument name. + * + * This routine *should* be a static; don't use it. + */ +static char * +findenv(const char *name, int *offset) { + const char *np; + char **p, *c; + int len; + + if (name == NULL || environ == NULL) + return (NULL); + for (np = name; *np && *np != '='; ++np) + continue; + len = np - name; + for (p = environ; (c = *p) != NULL; ++p) + if (strncmp(c, name, len) == 0 && c[len] == '=') { + *offset = p - environ; + return (c + len + 1); + } + return (NULL); +} +#endif + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/bsd/setitimer.c b/contrib/bind-9.5.2/lib/bind/bsd/setitimer.c new file mode 100644 index 0000000000..67881d7ca8 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/bsd/setitimer.c @@ -0,0 +1,29 @@ +#ifndef LINT +static const char rcsid[] = "$Id: setitimer.c,v 1.2 2005/04/27 04:56:12 sra Exp $"; +#endif + +#include "port_before.h" + +#include + +#include "port_after.h" + +/*% + * Setitimer emulation routine. + */ +#ifndef NEED_SETITIMER +int __bindcompat_setitimer; +#else + +int +__setitimer(int which, const struct itimerval *value, + struct itimerval *ovalue) +{ + if (alarm(value->it_value.tv_sec) >= 0) + return (0); + else + return (-1); +} +#endif + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/bsd/strcasecmp.c b/contrib/bind-9.5.2/lib/bind/bsd/strcasecmp.c new file mode 100644 index 0000000000..0c9f0dccf0 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/bsd/strcasecmp.c @@ -0,0 +1,124 @@ +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)strcasecmp.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: strcasecmp.c,v 1.2 2005/04/27 04:56:12 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Copyright (c) 1987, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "port_before.h" + +#include +#include +#include + +#include + +#include "port_after.h" + +#ifndef NEED_STRCASECMP +int __strcasecmp_unneeded__; +#else + +/*% + * This array is designed for mapping upper and lower case letter + * together for a case independent comparison. The mappings are + * based upon ascii character sequences. + */ +static const u_char charmap[] = { + 0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007, + 0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017, + 0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027, + 0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037, + 0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047, + 0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057, + 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067, + 0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077, + 0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147, + 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157, + 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, + 0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137, + 0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147, + 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157, + 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, + 0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177, + 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207, + 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217, + 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227, + 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237, + 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, + 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257, + 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, + 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, + 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307, + 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317, + 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327, + 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, + 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, + 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357, + 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, + 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377 +}; + +int +strcasecmp(const char *s1, const char *s2) { + const u_char *cm = charmap, + *us1 = (const u_char *)s1, + *us2 = (const u_char *)s2; + + while (cm[*us1] == cm[*us2++]) + if (*us1++ == '\0') + return (0); + return (cm[*us1] - cm[*--us2]); +} + +int +strncasecmp(const char *s1, const char *s2, size_t n) { + if (n != 0) { + const u_char *cm = charmap, + *us1 = (const u_char *)s1, + *us2 = (const u_char *)s2; + + do { + if (cm[*us1] != cm[*us2++]) + return (cm[*us1] - cm[*--us2]); + if (*us1++ == '\0') + break; + } while (--n != 0); + } + return (0); +} + +#endif /*NEED_STRCASECMP*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/bsd/strdup.c b/contrib/bind-9.5.2/lib/bind/bsd/strdup.c new file mode 100644 index 0000000000..a8d31e9587 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/bsd/strdup.c @@ -0,0 +1,20 @@ +#include "port_before.h" + +#include + +#include "port_after.h" + +#ifndef NEED_STRDUP +int __bind_strdup_unneeded; +#else +char * +strdup(const char *src) { + char *dst = malloc(strlen(src) + 1); + + if (dst) + strcpy(dst, src); + return (dst); +} +#endif + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/bsd/strerror.c b/contrib/bind-9.5.2/lib/bind/bsd/strerror.c new file mode 100644 index 0000000000..7b12592948 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/bsd/strerror.c @@ -0,0 +1,94 @@ +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)strerror.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: strerror.c,v 1.5.672.1 2008/02/18 04:10:16 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "port_before.h" + +#include +#include + +#include + +#include "port_after.h" + +#ifndef NEED_STRERROR +int __strerror_unneeded__; +#else + +#ifdef USE_SYSERROR_LIST +extern int sys_nerr; +extern char *sys_errlist[]; +#endif + +const char * +isc_strerror(int num) { +#define UPREFIX "Unknown error: " + static char ebuf[40] = UPREFIX; /*%< 64-bit number + slop */ + u_int errnum; + char *p, *t; +#ifndef USE_SYSERROR_LIST + const char *ret; +#endif + char tmp[40]; + + errnum = num; /*%< convert to unsigned */ +#ifdef USE_SYSERROR_LIST + if (errnum < (u_int)sys_nerr) + return (sys_errlist[errnum]); +#else +#undef strerror + ret = strerror(num); /*%< call strerror() in libc */ + if (ret != NULL) + return(ret); +#endif + + /* Do this by hand, so we don't include stdio(3). */ + t = tmp; + do { + *t++ = "0123456789"[errnum % 10]; + } while (errnum /= 10); + for (p = ebuf + sizeof(UPREFIX) - 1;;) { + *p++ = *--t; + if (t <= tmp) + break; + } + return (ebuf); +} + +#endif /*NEED_STRERROR*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/bsd/strpbrk.c b/contrib/bind-9.5.2/lib/bind/bsd/strpbrk.c new file mode 100644 index 0000000000..4c12d88e1c --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/bsd/strpbrk.c @@ -0,0 +1,70 @@ +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)strpbrk.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: strpbrk.c,v 1.2 2005/04/27 04:56:12 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Copyright (c) 1985, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "port_before.h" + +#include +#include + +#include + +#include "port_after.h" + +#ifndef NEED_STRPBRK +int __strpbrk_unneeded__; +#else + +/*% + * Find the first occurrence in s1 of a character in s2 (excluding NUL). + */ +char * +strpbrk(const char *s1, const char *s2) { + const char *scanp; + int c, sc; + + while ((c = *s1++) != 0) { + for (scanp = s2; (sc = *scanp++) != 0;) + if (sc == c) + return ((char *)(s1 - 1)); + } + return (NULL); +} + +#endif /*NEED_STRPBRK*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/bsd/strsep.c b/contrib/bind-9.5.2/lib/bind/bsd/strsep.c new file mode 100644 index 0000000000..c7969f0028 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/bsd/strsep.c @@ -0,0 +1,88 @@ +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "strsep.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: strsep.c,v 1.2 2005/04/27 04:56:12 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "port_before.h" +#include +#include +#include +#include "port_after.h" + +#ifndef NEED_STRSEP +int __strsep_unneeded__; +#else + +/*% + * Get next token from string *stringp, where tokens are possibly-empty + * strings separated by characters from delim. + * + * Writes NULs into the string at *stringp to end tokens. + * delim need not remain constant from call to call. + * On return, *stringp points past the last NUL written (if there might + * be further tokens), or is NULL (if there are definitely no more tokens). + * + * If *stringp is NULL, strsep returns NULL. + */ +char * +strsep(char **stringp, const char *delim) { + char *s; + const char *spanp; + int c, sc; + char *tok; + + if ((s = *stringp) == NULL) + return (NULL); + for (tok = s;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} + +#endif /*NEED_STRSEP*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/bsd/strtoul.c b/contrib/bind-9.5.2/lib/bind/bsd/strtoul.c new file mode 100644 index 0000000000..d942df0720 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/bsd/strtoul.c @@ -0,0 +1,119 @@ +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: strtoul.c,v 1.3.672.1 2008/02/18 04:10:16 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "port_before.h" + +#include +#include + +#include +#include +#include +#include + +#include "port_after.h" + +#ifndef NEED_STRTOUL +int __strtoul_unneeded__; +#else + +/*% + * Convert a string to an unsigned long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +u_long +strtoul(const char *nptr, char **endptr, int base) { + const char *s = nptr; + u_long acc, cutoff; + int neg, c, any, cutlim; + + neg = 0; + + /* + * See strtol for comments as to the logic used. + */ + do { + c = *(const unsigned char *)s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + cutoff = (u_long)ULONG_MAX / (u_long)base; + cutlim = (u_long)ULONG_MAX % (u_long)base; + for (acc = 0, any = 0;; c = *(const unsigned char*)s++) { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = ULONG_MAX; + errno = ERANGE; + } else if (neg) + acc = -acc; + if (endptr != 0) + DE_CONST((any ? s - 1 : nptr), *endptr); + return (acc); +} + +#endif /*NEED_STRTOUL*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/bsd/utimes.c b/contrib/bind-9.5.2/lib/bind/bsd/utimes.c new file mode 100644 index 0000000000..2f65cffe25 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/bsd/utimes.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1997,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#include "port_before.h" + +#include +#include +#include + +#include "port_after.h" + +#ifndef NEED_UTIMES +int __bind_utimes_unneeded; +#else + +int +__utimes(char *filename, struct timeval *tvp) { + struct utimbuf utb; + + utb.actime = (time_t)tvp[0].tv_sec; + utb.modtime = (time_t)tvp[1].tv_sec; + return (utime(filename, &utb)); +} + +#endif /* NEED_UTIMES */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/bsd/writev.c b/contrib/bind-9.5.2/lib/bind/bsd/writev.c new file mode 100644 index 0000000000..65baa71cfc --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/bsd/writev.c @@ -0,0 +1,89 @@ +#ifndef LINT +static const char rcsid[] = "$Id: writev.c,v 1.3 2005/04/27 04:56:13 sra Exp $"; +#endif + +#include "port_before.h" + +#include +#include +#include +#include + +#include "port_after.h" + +#ifndef NEED_WRITEV +int __bindcompat_writev; +#else + +#ifdef _CRAY +#define OWN_WRITEV +int +__writev(int fd, struct iovec *iov, int iovlen) +{ + struct stat statbuf; + + if (fstat(fd, &statbuf) < 0) + return (-1); + + /* + * Allow for atomic writes to network. + */ + if (statbuf.st_mode & S_IFSOCK) { + struct msghdr mesg; + + memset(&mesg, 0, sizeof(mesg)); + mesg.msg_name = 0; + mesg.msg_namelen = 0; + mesg.msg_iov = iov; + mesg.msg_iovlen = iovlen; + mesg.msg_accrights = 0; + mesg.msg_accrightslen = 0; + return (sendmsg(fd, &mesg, 0)); + } else { + struct iovec *tv; + int i, rcode = 0, count = 0; + + for (i = 0, tv = iov; i <= iovlen; tv++) { + rcode = write(fd, tv->iov_base, tv->iov_len); + + if (rcode < 0) + break; + + count += rcode; + } + + if (count == 0) + return (rcode); + else + return (count); + } +} + +#else /*_CRAY*/ + +int +__writev(fd, vp, vpcount) + int fd; + const struct iovec *vp; + int vpcount; +{ + int count = 0; + + while (vpcount-- > 0) { + int written = write(fd, vp->iov_base, vp->iov_len); + + if (written < 0) + return (-1); + count += written; + if (written != vp->iov_len) + break; + vp++; + } + return (count); +} + +#endif /*_CRAY*/ + +#endif /*NEED_WRITEV*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/config.h.in b/contrib/bind-9.5.2/lib/bind/config.h.in new file mode 100644 index 0000000000..5e2a83defb --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/config.h.in @@ -0,0 +1,68 @@ +#undef _SOCKADDR_LEN +#undef HAVE_FCNTL_H +#undef HAVE_PATHS_H +#undef HAVE_INTTYPES_H +#undef HAVE_STROPTS_H +#undef HAVE_SYS_TIMERS_H +#undef HAVE_SYS_SELECT_H +#undef HAVE_MEMORY_H +#undef SYS_CDEFS_H +#undef _POSIX_PTHREAD_SEMANTICS +#undef POSIX_GETPWUID_R +#undef POSIX_GETPWNAM_R +#undef POSIX_GETGRGID_R +#undef POSIX_GETGRNAM_R +#undef HAVE_MEMMOVE +#undef HAVE_MEMCHR +#undef SPRINTF_CHAR +#undef VSPRINTF_CHAR +#undef USE_SYSERROR_LIST +#undef NEED_STRTOUL +#undef NEED_SUN4PROTOS +#undef REENABLE_SEND + +#undef NEED_SETGROUPENT +#undef NEED_GETGROUPLIST + +/* define if prototype for getgrnam_r() is required */ +#undef NEED_GETGRNAM_R +#undef NEED_GETGRGID_R +#undef NEED_GETGRENT_R +#undef NEED_SETGRENT_R +#undef NEED_ENDGRENT_R + +#undef NEED_INNETGR_R +#undef NEED_SETNETGRENT_R +#undef NEED_ENDNETGRENT_R + +#undef NEED_GETPWNAM_R +#undef NEED_GETPWUID_R +#undef NEED_SETPWENT_R +#undef NEED_SETPASSENT_R +#undef NEED_SETPWENT_R +#undef NEED_GETPWENT_R +#undef NEED_ENDPWENT_R + +#undef NEED_SETPASSENT + +#undef HAS_PW_CLASS + +#undef ssize_t +#undef uintptr_t + +/* Shut up warnings about sputaux in stdio.h on BSD/OS pre-4.1 */ +#undef SHUTUP_SPUTAUX +#ifdef SHUTUP_SPUTAUX +struct __sFILE; +extern __inline int __sputaux(int _c, struct __sFILE *_p); +#endif +#undef BROKEN_IN6ADDR_INIT_MACROS +#undef HAVE_STRLCAT +/* Shut up warnings about missing braces */ +#undef SHUTUP_MUTEX_INITIALIZER +#ifdef SHUTUP_MUTEX_INITIALIZER +#define LIBBIND_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER } +#else +#define LIBBIND_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +#endif + diff --git a/contrib/bind-9.5.2/lib/bind/dst/dst_api.c b/contrib/bind-9.5.2/lib/bind/dst/dst_api.c new file mode 100644 index 0000000000..f11f57b2c3 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/dst/dst_api.c @@ -0,0 +1,1048 @@ +#ifndef LINT +static const char rcsid[] = "$Header: /proj/cvs/prod/bind9/lib/bind/dst/Attic/dst_api.c,v 1.17 2007/09/24 17:18:25 each Exp $"; +#endif + +/* + * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc. + * + * Permission to use, copy modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * TRUSTED INFORMATION SYSTEMS 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 THE SOFTWARE. + */ +/* + * This file contains the interface between the DST API and the crypto API. + * This is the only file that needs to be changed if the crypto system is + * changed. Exported functions are: + * void dst_init() Initialize the toolkit + * int dst_check_algorithm() Function to determines if alg is suppored. + * int dst_compare_keys() Function to compare two keys for equality. + * int dst_sign_data() Incremental signing routine. + * int dst_verify_data() Incremental verify routine. + * int dst_generate_key() Function to generate new KEY + * DST_KEY *dst_read_key() Function to retrieve private/public KEY. + * void dst_write_key() Function to write out a key. + * DST_KEY *dst_dnskey_to_key() Function to convert DNS KEY RR to a DST + * KEY structure. + * int dst_key_to_dnskey() Function to return a public key in DNS + * format binary + * DST_KEY *dst_buffer_to_key() Converst a data in buffer to KEY + * int *dst_key_to_buffer() Writes out DST_KEY key matterial in buffer + * void dst_free_key() Releases all memory referenced by key structure + */ + +#include "port_before.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dst_internal.h" +#include "port_after.h" + +/* static variables */ +static int done_init = 0; +dst_func *dst_t_func[DST_MAX_ALGS]; +const char *key_file_fmt_str = "Private-key-format: v%s\nAlgorithm: %d (%s)\n"; +const char *dst_path = ""; + +/* internal I/O functions */ +static DST_KEY *dst_s_read_public_key(const char *in_name, + const u_int16_t in_id, int in_alg); +static int dst_s_read_private_key_file(char *name, DST_KEY *pk_key, + u_int16_t in_id, int in_alg); +static int dst_s_write_public_key(const DST_KEY *key); +static int dst_s_write_private_key(const DST_KEY *key); + +/* internal function to set up data structure */ +static DST_KEY *dst_s_get_key_struct(const char *name, const int alg, + const int flags, const int protocol, + const int bits); + +/*% + * dst_init + * This function initializes the Digital Signature Toolkit. + * Right now, it just checks the DSTKEYPATH environment variable. + * Parameters + * none + * Returns + * none + */ +void +dst_init() +{ + char *s; + int len; + + if (done_init != 0) + return; + done_init = 1; + + s = getenv("DSTKEYPATH"); + len = 0; + if (s) { + struct stat statbuf; + + len = strlen(s); + if (len > PATH_MAX) { + EREPORT(("%s is longer than %d characters, ignoring\n", + s, PATH_MAX)); + } else if (stat(s, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) { + EREPORT(("%s is not a valid directory\n", s)); + } else { + char *tmp; + tmp = (char *) malloc(len + 2); + memcpy(tmp, s, len + 1); + if (tmp[strlen(tmp) - 1] != '/') { + tmp[strlen(tmp) + 1] = 0; + tmp[strlen(tmp)] = '/'; + } + dst_path = tmp; + } + } + memset(dst_t_func, 0, sizeof(dst_t_func)); + /* first one is selected */ + dst_hmac_md5_init(); +} + +/*% + * dst_check_algorithm + * This function determines if the crypto system for the specified + * algorithm is present. + * Parameters + * alg 1 KEY_RSA + * 3 KEY_DSA + * 157 KEY_HMAC_MD5 + * future algorithms TBD and registered with IANA. + * Returns + * 1 - The algorithm is available. + * 0 - The algorithm is not available. + */ +int +dst_check_algorithm(const int alg) +{ + return (dst_t_func[alg] != NULL); +} + +/*% + * dst_s_get_key_struct + * This function allocates key structure and fills in some of the + * fields of the structure. + * Parameters: + * name: the name of the key + * alg: the algorithm number + * flags: the dns flags of the key + * protocol: the dns protocol of the key + * bits: the size of the key + * Returns: + * NULL if error + * valid pointer otherwise + */ +static DST_KEY * +dst_s_get_key_struct(const char *name, const int alg, const int flags, + const int protocol, const int bits) +{ + DST_KEY *new_key = NULL; + + if (dst_check_algorithm(alg)) /*%< make sure alg is available */ + new_key = (DST_KEY *) malloc(sizeof(*new_key)); + if (new_key == NULL) + return (NULL); + + memset(new_key, 0, sizeof(*new_key)); + new_key->dk_key_name = strdup(name); + if (new_key->dk_key_name == NULL) { + free(new_key); + return (NULL); + } + new_key->dk_alg = alg; + new_key->dk_flags = flags; + new_key->dk_proto = protocol; + new_key->dk_KEY_struct = NULL; + new_key->dk_key_size = bits; + new_key->dk_func = dst_t_func[alg]; + return (new_key); +} + +/*% + * dst_compare_keys + * Compares two keys for equality. + * Parameters + * key1, key2 Two keys to be compared. + * Returns + * 0 The keys are equal. + * non-zero The keys are not equal. + */ + +int +dst_compare_keys(const DST_KEY *key1, const DST_KEY *key2) +{ + if (key1 == key2) + return (0); + if (key1 == NULL || key2 == NULL) + return (4); + if (key1->dk_alg != key2->dk_alg) + return (1); + if (key1->dk_key_size != key2->dk_key_size) + return (2); + if (key1->dk_id != key2->dk_id) + return (3); + return (key1->dk_func->compare(key1, key2)); +} + +/*% + * dst_sign_data + * An incremental signing function. Data is signed in steps. + * First the context must be initialized (SIG_MODE_INIT). + * Then data is hashed (SIG_MODE_UPDATE). Finally the signature + * itself is created (SIG_MODE_FINAL). This function can be called + * once with INIT, UPDATE and FINAL modes all set, or it can be + * called separately with a different mode set for each step. The + * UPDATE step can be repeated. + * Parameters + * mode A bit mask used to specify operation(s) to be performed. + * SIG_MODE_INIT 1 Initialize digest + * SIG_MODE_UPDATE 2 Add data to digest + * SIG_MODE_FINAL 4 Generate signature + * from signature + * SIG_MODE_ALL (SIG_MODE_INIT,SIG_MODE_UPDATE,SIG_MODE_FINAL + * data Data to be signed. + * len The length in bytes of data to be signed. + * in_key Contains a private key to sign with. + * KEY structures should be handled (created, converted, + * compared, stored, freed) by the DST. + * signature + * The location to which the signature will be written. + * sig_len Length of the signature field in bytes. + * Return + * 0 Successfull INIT or Update operation + * >0 success FINAL (sign) operation + * <0 failure + */ + +int +dst_sign_data(const int mode, DST_KEY *in_key, void **context, + const u_char *data, const int len, + u_char *signature, const int sig_len) +{ + DUMP(data, mode, len, "dst_sign_data()"); + + if (mode & SIG_MODE_FINAL && + (in_key->dk_KEY_struct == NULL || signature == NULL)) + return (MISSING_KEY_OR_SIGNATURE); + + if (in_key->dk_func && in_key->dk_func->sign) + return (in_key->dk_func->sign(mode, in_key, context, data, len, + signature, sig_len)); + return (UNKNOWN_KEYALG); +} + +/*% + * dst_verify_data + * An incremental verify function. Data is verified in steps. + * First the context must be initialized (SIG_MODE_INIT). + * Then data is hashed (SIG_MODE_UPDATE). Finally the signature + * is verified (SIG_MODE_FINAL). This function can be called + * once with INIT, UPDATE and FINAL modes all set, or it can be + * called separately with a different mode set for each step. The + * UPDATE step can be repeated. + * Parameters + * mode Operations to perform this time. + * SIG_MODE_INIT 1 Initialize digest + * SIG_MODE_UPDATE 2 add data to digest + * SIG_MODE_FINAL 4 verify signature + * SIG_MODE_ALL + * (SIG_MODE_INIT,SIG_MODE_UPDATE,SIG_MODE_FINAL) + * data Data to pass through the hash function. + * len Length of the data in bytes. + * in_key Key for verification. + * signature Location of signature. + * sig_len Length of the signature in bytes. + * Returns + * 0 Verify success + * Non-Zero Verify Failure + */ + +int +dst_verify_data(const int mode, DST_KEY *in_key, void **context, + const u_char *data, const int len, + const u_char *signature, const int sig_len) +{ + DUMP(data, mode, len, "dst_verify_data()"); + if (mode & SIG_MODE_FINAL && + (in_key->dk_KEY_struct == NULL || signature == NULL)) + return (MISSING_KEY_OR_SIGNATURE); + + if (in_key->dk_func == NULL || in_key->dk_func->verify == NULL) + return (UNSUPPORTED_KEYALG); + return (in_key->dk_func->verify(mode, in_key, context, data, len, + signature, sig_len)); +} + +/*% + * dst_read_private_key + * Access a private key. First the list of private keys that have + * already been read in is searched, then the key accessed on disk. + * If the private key can be found, it is returned. If the key cannot + * be found, a null pointer is returned. The options specify required + * key characteristics. If the private key requested does not have + * these characteristics, it will not be read. + * Parameters + * in_keyname The private key name. + * in_id The id of the private key. + * options DST_FORCE_READ Read from disk - don't use a previously + * read key. + * DST_CAN_SIGN The key must be useable for signing. + * DST_NO_AUTHEN The key must be useable for authentication. + * DST_STANDARD Return any key + * Returns + * NULL If there is no key found in the current directory or + * this key has not been loaded before. + * !NULL Success - KEY structure returned. + */ + +DST_KEY * +dst_read_key(const char *in_keyname, const u_int16_t in_id, + const int in_alg, const int type) +{ + char keyname[PATH_MAX]; + DST_KEY *dg_key = NULL, *pubkey = NULL; + + if (!dst_check_algorithm(in_alg)) { /*%< make sure alg is available */ + EREPORT(("dst_read_private_key(): Algorithm %d not suppored\n", + in_alg)); + return (NULL); + } + if ((type & (DST_PUBLIC | DST_PRIVATE)) == 0) + return (NULL); + if (in_keyname == NULL) { + EREPORT(("dst_read_private_key(): Null key name passed in\n")); + return (NULL); + } else if (strlen(in_keyname) >= sizeof(keyname)) { + EREPORT(("dst_read_private_key(): keyname too big\n")); + return (NULL); + } else + strcpy(keyname, in_keyname); + + /* before I read in the public key, check if it is allowed to sign */ + if ((pubkey = dst_s_read_public_key(keyname, in_id, in_alg)) == NULL) + return (NULL); + + if (type == DST_PUBLIC) + return pubkey; + + if (!(dg_key = dst_s_get_key_struct(keyname, pubkey->dk_alg, + pubkey->dk_flags, pubkey->dk_proto, + 0))) + return (dg_key); + /* Fill in private key and some fields in the general key structure */ + if (dst_s_read_private_key_file(keyname, dg_key, pubkey->dk_id, + pubkey->dk_alg) == 0) + dg_key = dst_free_key(dg_key); + + (void)dst_free_key(pubkey); + return (dg_key); +} + +int +dst_write_key(const DST_KEY *key, const int type) +{ + int pub = 0, priv = 0; + + if (key == NULL) + return (0); + if (!dst_check_algorithm(key->dk_alg)) { /*%< make sure alg is available */ + EREPORT(("dst_write_key(): Algorithm %d not suppored\n", + key->dk_alg)); + return (UNSUPPORTED_KEYALG); + } + if ((type & (DST_PRIVATE|DST_PUBLIC)) == 0) + return (0); + + if (type & DST_PUBLIC) + if ((pub = dst_s_write_public_key(key)) < 0) + return (pub); + if (type & DST_PRIVATE) + if ((priv = dst_s_write_private_key(key)) < 0) + return (priv); + return (priv+pub); +} + +/*% + * dst_write_private_key + * Write a private key to disk. The filename will be of the form: + * K<key->dk_name>+<key->dk_alg+><key-d>k_id.><private key suffix>. + * If there is already a file with this name, an error is returned. + * + * Parameters + * key A DST managed key structure that contains + * all information needed about a key. + * Return + * >= 0 Correct behavior. Returns length of encoded key value + * written to disk. + * < 0 error. + */ + +static int +dst_s_write_private_key(const DST_KEY *key) +{ + u_char encoded_block[RAW_KEY_SIZE]; + char file[PATH_MAX]; + int len; + FILE *fp; + + /* First encode the key into the portable key format */ + if (key == NULL) + return (-1); + if (key->dk_KEY_struct == NULL) + return (0); /*%< null key has no private key */ + if (key->dk_func == NULL || key->dk_func->to_file_fmt == NULL) { + EREPORT(("dst_write_private_key(): Unsupported operation %d\n", + key->dk_alg)); + return (-5); + } else if ((len = key->dk_func->to_file_fmt(key, (char *)encoded_block, + sizeof(encoded_block))) <= 0) { + EREPORT(("dst_write_private_key(): Failed encoding private RSA bsafe key %d\n", len)); + return (-8); + } + /* Now I can create the file I want to use */ + dst_s_build_filename(file, key->dk_key_name, key->dk_id, key->dk_alg, + PRIVATE_KEY, PATH_MAX); + + /* Do not overwrite an existing file */ + if ((fp = dst_s_fopen(file, "w", 0600)) != NULL) { + int nn; + if ((nn = fwrite(encoded_block, 1, len, fp)) != len) { + EREPORT(("dst_write_private_key(): Write failure on %s %d != %d errno=%d\n", + file, len, nn, errno)); + fclose(fp); + return (-5); + } + fclose(fp); + } else { + EREPORT(("dst_write_private_key(): Can not create file %s\n" + ,file)); + return (-6); + } + memset(encoded_block, 0, len); + return (len); +} + +/*% +* + * dst_read_public_key + * Read a public key from disk and store in a DST key structure. + * Parameters + * in_name K<in_name><in_id>.<public key suffix> is the + * filename of the key file to be read. + * Returns + * NULL If the key does not exist or no name is supplied. + * NON-NULL Initialized key structure if the key exists. + */ + +static DST_KEY * +dst_s_read_public_key(const char *in_name, const u_int16_t in_id, int in_alg) +{ + int flags, proto, alg, len, dlen; + int c; + char name[PATH_MAX], enckey[RAW_KEY_SIZE], *notspace; + u_char deckey[RAW_KEY_SIZE]; + FILE *fp; + + if (in_name == NULL) { + EREPORT(("dst_read_public_key(): No key name given\n")); + return (NULL); + } + if (dst_s_build_filename(name, in_name, in_id, in_alg, PUBLIC_KEY, + PATH_MAX) == -1) { + EREPORT(("dst_read_public_key(): Cannot make filename from %s, %d, and %s\n", + in_name, in_id, PUBLIC_KEY)); + return (NULL); + } + /* + * Open the file and read it's formatted contents up to key + * File format: + * domain.name [ttl] [IN] KEY <flags> <protocol> <algorithm> <key> + * flags, proto, alg stored as decimal (or hex numbers FIXME). + * (FIXME: handle parentheses for line continuation.) + */ + if ((fp = dst_s_fopen(name, "r", 0)) == NULL) { + EREPORT(("dst_read_public_key(): Public Key not found %s\n", + name)); + return (NULL); + } + /* Skip domain name, which ends at first blank */ + while ((c = getc(fp)) != EOF) + if (isspace(c)) + break; + /* Skip blank to get to next field */ + while ((c = getc(fp)) != EOF) + if (!isspace(c)) + break; + + /* Skip optional TTL -- if initial digit, skip whole word. */ + if (isdigit(c)) { + while ((c = getc(fp)) != EOF) + if (isspace(c)) + break; + while ((c = getc(fp)) != EOF) + if (!isspace(c)) + break; + } + /* Skip optional "IN" */ + if (c == 'I' || c == 'i') { + while ((c = getc(fp)) != EOF) + if (isspace(c)) + break; + while ((c = getc(fp)) != EOF) + if (!isspace(c)) + break; + } + /* Locate and skip "KEY" */ + if (c != 'K' && c != 'k') { + EREPORT(("\"KEY\" doesn't appear in file: %s", name)); + return NULL; + } + while ((c = getc(fp)) != EOF) + if (isspace(c)) + break; + while ((c = getc(fp)) != EOF) + if (!isspace(c)) + break; + ungetc(c, fp); /*%< return the charcter to the input field */ + /* Handle hex!! FIXME. */ + + if (fscanf(fp, "%d %d %d", &flags, &proto, &alg) != 3) { + EREPORT(("dst_read_public_key(): Can not read flag/proto/alg field from %s\n" + ,name)); + return (NULL); + } + /* read in the key string */ + fgets(enckey, sizeof(enckey), fp); + + /* If we aren't at end-of-file, something is wrong. */ + while ((c = getc(fp)) != EOF) + if (!isspace(c)) + break; + if (!feof(fp)) { + EREPORT(("Key too long in file: %s", name)); + return NULL; + } + fclose(fp); + + if ((len = strlen(enckey)) <= 0) + return (NULL); + + /* discard \n */ + enckey[--len] = '\0'; + + /* remove leading spaces */ + for (notspace = (char *) enckey; isspace((*notspace)&0xff); len--) + notspace++; + + dlen = b64_pton(notspace, deckey, sizeof(deckey)); + if (dlen < 0) { + EREPORT(("dst_read_public_key: bad return from b64_pton = %d", + dlen)); + return (NULL); + } + /* store key and info in a key structure that is returned */ +/* return dst_store_public_key(in_name, alg, proto, 666, flags, deckey, + dlen);*/ + return dst_buffer_to_key(in_name, alg, flags, proto, deckey, dlen); +} + +/*% + * dst_write_public_key + * Write a key to disk in DNS format. + * Parameters + * key Pointer to a DST key structure. + * Returns + * 0 Failure + * 1 Success + */ + +static int +dst_s_write_public_key(const DST_KEY *key) +{ + FILE *fp; + char filename[PATH_MAX]; + u_char out_key[RAW_KEY_SIZE]; + char enc_key[RAW_KEY_SIZE]; + int len = 0; + int mode; + + memset(out_key, 0, sizeof(out_key)); + if (key == NULL) { + EREPORT(("dst_write_public_key(): No key specified \n")); + return (0); + } else if ((len = dst_key_to_dnskey(key, out_key, sizeof(out_key)))< 0) + return (0); + + /* Make the filename */ + if (dst_s_build_filename(filename, key->dk_key_name, key->dk_id, + key->dk_alg, PUBLIC_KEY, PATH_MAX) == -1) { + EREPORT(("dst_write_public_key(): Cannot make filename from %s, %d, and %s\n", + key->dk_key_name, key->dk_id, PUBLIC_KEY)); + return (0); + } + /* XXX in general this should be a check for symmetric keys */ + mode = (key->dk_alg == KEY_HMAC_MD5) ? 0600 : 0644; + /* create public key file */ + if ((fp = dst_s_fopen(filename, "w+", mode)) == NULL) { + EREPORT(("DST_write_public_key: open of file:%s failed (errno=%d)\n", + filename, errno)); + return (0); + } + /*write out key first base64 the key data */ + if (key->dk_flags & DST_EXTEND_FLAG) + b64_ntop(&out_key[6], len - 6, enc_key, sizeof(enc_key)); + else + b64_ntop(&out_key[4], len - 4, enc_key, sizeof(enc_key)); + fprintf(fp, "%s IN KEY %d %d %d %s\n", + key->dk_key_name, + key->dk_flags, key->dk_proto, key->dk_alg, enc_key); + fclose(fp); + return (1); +} + +/*% + * dst_dnskey_to_public_key + * This function converts the contents of a DNS KEY RR into a DST + * key structure. + * Paramters + * len Length of the RDATA of the KEY RR RDATA + * rdata A pointer to the the KEY RR RDATA. + * in_name Key name to be stored in key structure. + * Returns + * NULL Failure + * NON-NULL Success. Pointer to key structure. + * Caller's responsibility to free() it. + */ + +DST_KEY * +dst_dnskey_to_key(const char *in_name, const u_char *rdata, const int len) +{ + DST_KEY *key_st; + int alg ; + int start = DST_KEY_START; + + if (rdata == NULL || len <= DST_KEY_ALG) /*%< no data */ + return (NULL); + alg = (u_int8_t) rdata[DST_KEY_ALG]; + if (!dst_check_algorithm(alg)) { /*%< make sure alg is available */ + EREPORT(("dst_dnskey_to_key(): Algorithm %d not suppored\n", + alg)); + return (NULL); + } + + if (in_name == NULL) + return (NULL); + + if ((key_st = dst_s_get_key_struct(in_name, alg, 0, 0, 0)) == NULL) + return (NULL); + + key_st->dk_id = dst_s_dns_key_id(rdata, len); + key_st->dk_flags = dst_s_get_int16(rdata); + key_st->dk_proto = (u_int16_t) rdata[DST_KEY_PROT]; + if (key_st->dk_flags & DST_EXTEND_FLAG) { + u_int32_t ext_flags; + ext_flags = (u_int32_t) dst_s_get_int16(&rdata[DST_EXT_FLAG]); + key_st->dk_flags = key_st->dk_flags | (ext_flags << 16); + start += 2; + } + /* + * now point to the begining of the data representing the encoding + * of the key + */ + if (key_st->dk_func && key_st->dk_func->from_dns_key) { + if (key_st->dk_func->from_dns_key(key_st, &rdata[start], + len - start) > 0) + return (key_st); + } else + EREPORT(("dst_dnskey_to_public_key(): unsuppored alg %d\n", + alg)); + + SAFE_FREE(key_st); + return (key_st); +} + +/*% + * dst_public_key_to_dnskey + * Function to encode a public key into DNS KEY wire format + * Parameters + * key Key structure to encode. + * out_storage Location to write the encoded key to. + * out_len Size of the output array. + * Returns + * <0 Failure + * >=0 Number of bytes written to out_storage + */ + +int +dst_key_to_dnskey(const DST_KEY *key, u_char *out_storage, + const int out_len) +{ + u_int16_t val; + int loc = 0; + int enc_len = 0; + if (key == NULL) + return (-1); + + if (!dst_check_algorithm(key->dk_alg)) { /*%< make sure alg is available */ + EREPORT(("dst_key_to_dnskey(): Algorithm %d not suppored\n", + key->dk_alg)); + return (UNSUPPORTED_KEYALG); + } + memset(out_storage, 0, out_len); + val = (u_int16_t)(key->dk_flags & 0xffff); + dst_s_put_int16(out_storage, val); + loc += 2; + + out_storage[loc++] = (u_char) key->dk_proto; + out_storage[loc++] = (u_char) key->dk_alg; + + if (key->dk_flags > 0xffff) { /*%< Extended flags */ + val = (u_int16_t)((key->dk_flags >> 16) & 0xffff); + dst_s_put_int16(&out_storage[loc], val); + loc += 2; + } + if (key->dk_KEY_struct == NULL) + return (loc); + if (key->dk_func && key->dk_func->to_dns_key) { + enc_len = key->dk_func->to_dns_key(key, + (u_char *) &out_storage[loc], + out_len - loc); + if (enc_len > 0) + return (enc_len + loc); + else + return (-1); + } else + EREPORT(("dst_key_to_dnskey(): Unsupported ALG %d\n", + key->dk_alg)); + return (-1); +} + +/*% + * dst_buffer_to_key + * Function to encode a string of raw data into a DST key + * Parameters + * alg The algorithm (HMAC only) + * key A pointer to the data + * keylen The length of the data + * Returns + * NULL an error occurred + * NON-NULL the DST key + */ +DST_KEY * +dst_buffer_to_key(const char *key_name, /*!< name of the key */ + const int alg, /*!< algorithm */ + const int flags, /*!< dns flags */ + const int protocol, /*!< dns protocol */ + const u_char *key_buf, /*!< key in dns wire fmt */ + const int key_len) /*!< size of key */ +{ + + DST_KEY *dkey = NULL; + int dnslen; + u_char dns[2048]; + + if (!dst_check_algorithm(alg)) { /*%< make sure alg is available */ + EREPORT(("dst_buffer_to_key(): Algorithm %d not suppored\n", alg)); + return (NULL); + } + + dkey = dst_s_get_key_struct(key_name, alg, flags, protocol, -1); + + if (dkey == NULL || dkey->dk_func == NULL || + dkey->dk_func->from_dns_key == NULL) + return (dst_free_key(dkey)); + + if (dkey->dk_func->from_dns_key(dkey, key_buf, key_len) < 0) { + EREPORT(("dst_buffer_to_key(): dst_buffer_to_hmac failed\n")); + return (dst_free_key(dkey)); + } + + dnslen = dst_key_to_dnskey(dkey, dns, sizeof(dns)); + dkey->dk_id = dst_s_dns_key_id(dns, dnslen); + return (dkey); +} + +int +dst_key_to_buffer(DST_KEY *key, u_char *out_buff, int buf_len) +{ + int len; + /* this function will extrac the secret of HMAC into a buffer */ + if (key == NULL) + return (0); + if (key->dk_func != NULL && key->dk_func->to_dns_key != NULL) { + len = key->dk_func->to_dns_key(key, out_buff, buf_len); + if (len < 0) + return (0); + return (len); + } + return (0); +} + +/*% + * dst_s_read_private_key_file + * Function reads in private key from a file. + * Fills out the KEY structure. + * Parameters + * name Name of the key to be read. + * pk_key Structure that the key is returned in. + * in_id Key identifier (tag) + * Return + * 1 if everthing works + * 0 if there is any problem + */ + +static int +dst_s_read_private_key_file(char *name, DST_KEY *pk_key, u_int16_t in_id, + int in_alg) +{ + int cnt, alg, len, major, minor, file_major, file_minor; + int ret, id; + char filename[PATH_MAX]; + u_char in_buff[RAW_KEY_SIZE], *p; + FILE *fp; + int dnslen; + u_char dns[2048]; + + if (name == NULL || pk_key == NULL) { + EREPORT(("dst_read_private_key_file(): No key name given\n")); + return (0); + } + /* Make the filename */ + if (dst_s_build_filename(filename, name, in_id, in_alg, PRIVATE_KEY, + PATH_MAX) == -1) { + EREPORT(("dst_read_private_key(): Cannot make filename from %s, %d, and %s\n", + name, in_id, PRIVATE_KEY)); + return (0); + } + /* first check if we can find the key file */ + if ((fp = dst_s_fopen(filename, "r", 0)) == NULL) { + EREPORT(("dst_s_read_private_key_file: Could not open file %s in directory %s\n", + filename, dst_path[0] ? dst_path : + (char *) getcwd(NULL, PATH_MAX - 1))); + return (0); + } + /* now read the header info from the file */ + if ((cnt = fread(in_buff, 1, sizeof(in_buff), fp)) < 5) { + fclose(fp); + EREPORT(("dst_s_read_private_key_file: error reading file %s (empty file)\n", + filename)); + return (0); + } + /* decrypt key */ + fclose(fp); + if (memcmp(in_buff, "Private-key-format: v", 20) != 0) + goto fail; + len = cnt; + p = in_buff; + + if (!dst_s_verify_str((const char **) (void *)&p, + "Private-key-format: v")) { + EREPORT(("dst_s_read_private_key_file(): Not a Key file/Decrypt failed %s\n", name)); + goto fail; + } + /* read in file format */ + sscanf((char *)p, "%d.%d", &file_major, &file_minor); + sscanf(KEY_FILE_FORMAT, "%d.%d", &major, &minor); + if (file_major < 1) { + EREPORT(("dst_s_read_private_key_file(): Unknown keyfile %d.%d version for %s\n", + file_major, file_minor, name)); + goto fail; + } else if (file_major > major || file_minor > minor) + EREPORT(( + "dst_s_read_private_key_file(): Keyfile %s version higher than mine %d.%d MAY FAIL\n", + name, file_major, file_minor)); + + while (*p++ != '\n') ; /*%< skip to end of line */ + + if (!dst_s_verify_str((const char **) (void *)&p, "Algorithm: ")) + goto fail; + + if (sscanf((char *)p, "%d", &alg) != 1) + goto fail; + while (*p++ != '\n') ; /*%< skip to end of line */ + + if (pk_key->dk_key_name && !strcmp(pk_key->dk_key_name, name)) + SAFE_FREE2(pk_key->dk_key_name, strlen(pk_key->dk_key_name)); + pk_key->dk_key_name = (char *) strdup(name); + + /* allocate and fill in key structure */ + if (pk_key->dk_func == NULL || pk_key->dk_func->from_file_fmt == NULL) + goto fail; + + ret = pk_key->dk_func->from_file_fmt(pk_key, (char *)p, &in_buff[len] - p); + if (ret < 0) + goto fail; + + dnslen = dst_key_to_dnskey(pk_key, dns, sizeof(dns)); + id = dst_s_dns_key_id(dns, dnslen); + + /* Make sure the actual key tag matches the input tag used in the filename + */ + if (id != in_id) { + EREPORT(("dst_s_read_private_key_file(): actual tag of key read %d != input tag used to build filename %d.\n", id, in_id)); + goto fail; + } + pk_key->dk_id = (u_int16_t) id; + pk_key->dk_alg = alg; + memset(in_buff, 0, cnt); + return (1); + + fail: + memset(in_buff, 0, cnt); + return (0); +} + +/*% + * Generate and store a public/private keypair. + * Keys will be stored in formatted files. + * + * Parameters + & + *\par name Name of the new key. Used to create key files + *\li K<name>+<alg>+<id>.public and K<name>+<alg>+<id>.private. + *\par bits Size of the new key in bits. + *\par exp What exponent to use: + *\li 0 use exponent 3 + *\li non-zero use Fermant4 + *\par flags The default value of the DNS Key flags. + *\li The DNS Key RR Flag field is defined in RFC2065, + * section 3.3. The field has 16 bits. + *\par protocol + *\li Default value of the DNS Key protocol field. + *\li The DNS Key protocol field is defined in RFC2065, + * section 3.4. The field has 8 bits. + *\par alg What algorithm to use. Currently defined: + *\li KEY_RSA 1 + *\li KEY_DSA 3 + *\li KEY_HMAC 157 + *\par out_id The key tag is returned. + * + * Return + *\li NULL Failure + *\li non-NULL the generated key pair + * Caller frees the result, and its dk_name pointer. + */ +DST_KEY * +dst_generate_key(const char *name, const int bits, const int exp, + const int flags, const int protocol, const int alg) +{ + DST_KEY *new_key = NULL; + int dnslen; + u_char dns[2048]; + + if (name == NULL) + return (NULL); + + if (!dst_check_algorithm(alg)) { /*%< make sure alg is available */ + EREPORT(("dst_generate_key(): Algorithm %d not suppored\n", alg)); + return (NULL); + } + + new_key = dst_s_get_key_struct(name, alg, flags, protocol, bits); + if (new_key == NULL) + return (NULL); + if (bits == 0) /*%< null key we are done */ + return (new_key); + if (new_key->dk_func == NULL || new_key->dk_func->generate == NULL) { + EREPORT(("dst_generate_key_pair():Unsupported algorithm %d\n", + alg)); + return (dst_free_key(new_key)); + } + if (new_key->dk_func->generate(new_key, exp) <= 0) { + EREPORT(("dst_generate_key_pair(): Key generation failure %s %d %d %d\n", + new_key->dk_key_name, new_key->dk_alg, + new_key->dk_key_size, exp)); + return (dst_free_key(new_key)); + } + + dnslen = dst_key_to_dnskey(new_key, dns, sizeof(dns)); + if (dnslen != UNSUPPORTED_KEYALG) + new_key->dk_id = dst_s_dns_key_id(dns, dnslen); + else + new_key->dk_id = 0; + + return (new_key); +} + +/*% + * Release all data structures pointed to by a key structure. + * + * Parameters + *\li f_key Key structure to be freed. + */ + +DST_KEY * +dst_free_key(DST_KEY *f_key) +{ + + if (f_key == NULL) + return (f_key); + if (f_key->dk_func && f_key->dk_func->destroy) + f_key->dk_KEY_struct = + f_key->dk_func->destroy(f_key->dk_KEY_struct); + else { + EREPORT(("dst_free_key(): Unknown key alg %d\n", + f_key->dk_alg)); + } + if (f_key->dk_KEY_struct) { + free(f_key->dk_KEY_struct); + f_key->dk_KEY_struct = NULL; + } + if (f_key->dk_key_name) + SAFE_FREE(f_key->dk_key_name); + SAFE_FREE(f_key); + return (NULL); +} + +/*% + * Return the maximim size of signature from the key specified in bytes + * + * Parameters + *\li key + * + * Returns + * \li bytes + */ +int +dst_sig_size(DST_KEY *key) { + switch (key->dk_alg) { + case KEY_HMAC_MD5: + return (16); + case KEY_HMAC_SHA1: + return (20); + case KEY_RSA: + return (key->dk_key_size + 7) / 8; + case KEY_DSA: + return (40); + default: + EREPORT(("dst_sig_size(): Unknown key alg %d\n", key->dk_alg)); + return -1; + } +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/dst/dst_internal.h b/contrib/bind-9.5.2/lib/bind/dst/dst_internal.h new file mode 100644 index 0000000000..e9bc6fc08d --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/dst/dst_internal.h @@ -0,0 +1,155 @@ +#ifndef DST_INTERNAL_H +#define DST_INTERNAL_H + +/* + * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc. + * + * Permission to use, copy modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * TRUSTED INFORMATION SYSTEMS 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 THE SOFTWARE. + */ +#include +#include +#if (!defined(BSD)) || (BSD < 199306) +# include +#else +# include +#endif + +#ifndef PATH_MAX +# ifdef POSIX_PATH_MAX +# define PATH_MAX POSIX_PATH_MAX +# else +# define PATH_MAX 255 /*%< this is the value of POSIX_PATH_MAX */ +# endif +#endif + +typedef struct dst_key { + char *dk_key_name; /*%< name of the key */ + int dk_key_size; /*%< this is the size of the key in bits */ + int dk_proto; /*%< what protocols this key can be used for */ + int dk_alg; /*%< algorithm number from key record */ + u_int32_t dk_flags; /*%< and the flags of the public key */ + u_int16_t dk_id; /*%< identifier of the key */ + void *dk_KEY_struct; /*%< pointer to key in crypto pkg fmt */ + struct dst_func *dk_func; /*%< point to cryptto pgk specific function table */ +} DST_KEY; +#define HAS_DST_KEY + +#include +/* + * define what crypto systems are supported for RSA, + * BSAFE is prefered over RSAREF; only one can be set at any time + */ +#if defined(BSAFE) && defined(RSAREF) +# error "Cannot have both BSAFE and RSAREF defined" +#endif + +/* Declare dst_lib specific constants */ +#define KEY_FILE_FORMAT "1.2" + +/* suffixes for key file names */ +#define PRIVATE_KEY "private" +#define PUBLIC_KEY "key" + +/* error handling */ +#ifdef REPORT_ERRORS +#define EREPORT(str) printf str +#else +#define EREPORT(str) (void)0 +#endif + +/* use our own special macro to FRRE memory */ + +#ifndef SAFE_FREE +#define SAFE_FREE(a) \ +do{if(a != NULL){memset(a,0, sizeof(*a)); free(a); a=NULL;}} while (0) +#define SAFE_FREE2(a,s) if (a != NULL && (long)s > 0){memset(a,0, s);free(a); a=NULL;} +#endif + +typedef struct dst_func { + int (*sign)(const int mode, DST_KEY *key, void **context, + const u_int8_t *data, const int len, + u_int8_t *signature, const int sig_len); + int (*verify)(const int mode, DST_KEY *key, void **context, + const u_int8_t *data, const int len, + const u_int8_t *signature, const int sig_len); + int (*compare)(const DST_KEY *key1, const DST_KEY *key2); + int (*generate)(DST_KEY *key, int parms); + void *(*destroy)(void *key); + /* conversion functions */ + int (*to_dns_key)(const DST_KEY *key, u_int8_t *out, + const int out_len); + int (*from_dns_key)(DST_KEY *key, const u_int8_t *str, + const int str_len); + int (*to_file_fmt)(const DST_KEY *key, char *out, + const int out_len); + int (*from_file_fmt)(DST_KEY *key, const char *out, + const int out_len); + +} dst_func; + +extern dst_func *dst_t_func[DST_MAX_ALGS]; +extern const char *key_file_fmt_str; +extern const char *dst_path; + +#ifndef DST_HASH_SIZE +#define DST_HASH_SIZE 20 /*%< RIPEMD160 and SHA-1 are 20 bytes MD5 is 16 */ +#endif + +int dst_bsafe_init(void); + +int dst_rsaref_init(void); + +int dst_hmac_md5_init(void); + +int dst_cylink_init(void); + +int dst_eay_dss_init(void); + +/* from higher level support routines */ +int dst_s_calculate_bits( const u_int8_t *str, const int max_bits); +int dst_s_verify_str( const char **buf, const char *str); + + +/* conversion between dns names and key file names */ +size_t dst_s_filename_length( const char *name, const char *suffix); +int dst_s_build_filename( char *filename, const char *name, + u_int16_t id, int alg, const char *suffix, + size_t filename_length); + +FILE *dst_s_fopen (const char *filename, const char *mode, int perm); + +/*% + * read and write network byte order into u_int?_t + * all of these should be retired + */ +u_int16_t dst_s_get_int16( const u_int8_t *buf); +void dst_s_put_int16( u_int8_t *buf, const u_int16_t val); + +u_int32_t dst_s_get_int32( const u_int8_t *buf); +void dst_s_put_int32( u_int8_t *buf, const u_int32_t val); + +#ifdef DUMP +# undef DUMP +# define DUMP(a,b,c,d) dst_s_dump(a,b,c,d) +#else +# define DUMP(a,b,c,d) +#endif +void +dst_s_dump(const int mode, const u_char *data, const int size, + const char *msg); + + + +#endif /* DST_INTERNAL_H */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/dst/hmac_link.c b/contrib/bind-9.5.2/lib/bind/dst/hmac_link.c new file mode 100644 index 0000000000..c57ef2cfc0 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/dst/hmac_link.c @@ -0,0 +1,489 @@ +#ifdef HMAC_MD5 +#ifndef LINT +static const char rcsid[] = "$Header: /proj/cvs/prod/bind9/lib/bind/dst/Attic/hmac_link.c,v 1.8 2007/09/24 17:18:25 each Exp $"; +#endif +/* + * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc. + * + * Permission to use, copy modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * TRUSTED INFORMATION SYSTEMS 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 THE SOFTWARE. + */ + +/*% + * This file contains an implementation of the HMAC-MD5 algorithm. + */ +#include "port_before.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dst_internal.h" + +#ifdef USE_MD5 +# ifndef HAVE_MD5 +# include "md5.h" +# else +# ifdef SOLARIS2 +# include +# endif +# endif +# ifndef _MD5_H_ +# define _MD5_H_ 1 /*%< make sure we do not include rsaref md5.h file */ +# endif +#endif + +#include "port_after.h" + + +#define HMAC_LEN 64 +#define HMAC_IPAD 0x36 +#define HMAC_OPAD 0x5c +#define MD5_LEN 16 + + +typedef struct hmackey { + u_char hk_ipad[64], hk_opad[64]; +} HMAC_Key; + + +/************************************************************************** + * dst_hmac_md5_sign + * Call HMAC signing functions to sign a block of data. + * There are three steps to signing, INIT (initialize structures), + * UPDATE (hash (more) data), FINAL (generate a signature). This + * routine performs one or more of these steps. + * Parameters + * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL. + * priv_key key to use for signing. + * context the context to be used in this digest + * data data to be signed. + * len length in bytes of data. + * signature location to store signature. + * sig_len size of the signature location + * returns + * N Success on SIG_MODE_FINAL = returns signature length in bytes + * 0 Success on SIG_MODE_INIT and UPDATE + * <0 Failure + */ + +static int +dst_hmac_md5_sign(const int mode, DST_KEY *d_key, void **context, + const u_char *data, const int len, + u_char *signature, const int sig_len) +{ + HMAC_Key *key; + int sign_len = 0; + MD5_CTX *ctx = NULL; + + if (d_key == NULL || d_key->dk_KEY_struct == NULL) + return (-1); + + if (mode & SIG_MODE_INIT) + ctx = (MD5_CTX *) malloc(sizeof(*ctx)); + else if (context) + ctx = (MD5_CTX *) *context; + if (ctx == NULL) + return (-1); + + key = (HMAC_Key *) d_key->dk_KEY_struct; + + if (mode & SIG_MODE_INIT) { + MD5Init(ctx); + MD5Update(ctx, key->hk_ipad, HMAC_LEN); + } + + if ((mode & SIG_MODE_UPDATE) && (data && len > 0)) + MD5Update(ctx, data, len); + + if (mode & SIG_MODE_FINAL) { + if (signature == NULL || sig_len < MD5_LEN) + return (SIGN_FINAL_FAILURE); + MD5Final(signature, ctx); + + /* perform outer MD5 */ + MD5Init(ctx); + MD5Update(ctx, key->hk_opad, HMAC_LEN); + MD5Update(ctx, signature, MD5_LEN); + MD5Final(signature, ctx); + sign_len = MD5_LEN; + SAFE_FREE(ctx); + } + else { + if (context == NULL) + return (-1); + *context = (void *) ctx; + } + return (sign_len); +} + + +/************************************************************************** + * dst_hmac_md5_verify() + * Calls HMAC verification routines. There are three steps to + * verification, INIT (initialize structures), UPDATE (hash (more) data), + * FINAL (generate a signature). This routine performs one or more of + * these steps. + * Parameters + * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL. + * dkey key to use for verify. + * data data signed. + * len length in bytes of data. + * signature signature. + * sig_len length in bytes of signature. + * returns + * 0 Success + * <0 Failure + */ + +static int +dst_hmac_md5_verify(const int mode, DST_KEY *d_key, void **context, + const u_char *data, const int len, + const u_char *signature, const int sig_len) +{ + HMAC_Key *key; + MD5_CTX *ctx = NULL; + + if (d_key == NULL || d_key->dk_KEY_struct == NULL) + return (-1); + + if (mode & SIG_MODE_INIT) + ctx = (MD5_CTX *) malloc(sizeof(*ctx)); + else if (context) + ctx = (MD5_CTX *) *context; + if (ctx == NULL) + return (-1); + + key = (HMAC_Key *) d_key->dk_KEY_struct; + if (mode & SIG_MODE_INIT) { + MD5Init(ctx); + MD5Update(ctx, key->hk_ipad, HMAC_LEN); + } + if ((mode & SIG_MODE_UPDATE) && (data && len > 0)) + MD5Update(ctx, data, len); + + if (mode & SIG_MODE_FINAL) { + u_char digest[MD5_LEN]; + if (signature == NULL || key == NULL || sig_len != MD5_LEN) + return (VERIFY_FINAL_FAILURE); + MD5Final(digest, ctx); + + /* perform outer MD5 */ + MD5Init(ctx); + MD5Update(ctx, key->hk_opad, HMAC_LEN); + MD5Update(ctx, digest, MD5_LEN); + MD5Final(digest, ctx); + + SAFE_FREE(ctx); + if (memcmp(digest, signature, MD5_LEN) != 0) + return (VERIFY_FINAL_FAILURE); + } + else { + if (context == NULL) + return (-1); + *context = (void *) ctx; + } + return (0); +} + + +/************************************************************************** + * dst_buffer_to_hmac_md5 + * Converts key from raw data to an HMAC Key + * This function gets in a pointer to the data + * Parameters + * hkey the HMAC key to be filled in + * key the key in raw format + * keylen the length of the key + * Return + * 0 Success + * <0 Failure + */ +static int +dst_buffer_to_hmac_md5(DST_KEY *dkey, const u_char *key, const int keylen) +{ + int i; + HMAC_Key *hkey = NULL; + MD5_CTX ctx; + int local_keylen = keylen; + u_char tk[MD5_LEN]; + + if (dkey == NULL || key == NULL || keylen < 0) + return (-1); + + if ((hkey = (HMAC_Key *) malloc(sizeof(HMAC_Key))) == NULL) + return (-2); + + memset(hkey->hk_ipad, 0, sizeof(hkey->hk_ipad)); + memset(hkey->hk_opad, 0, sizeof(hkey->hk_opad)); + + /* if key is longer than HMAC_LEN bytes reset it to key=MD5(key) */ + if (keylen > HMAC_LEN) { + MD5Init(&ctx); + MD5Update(&ctx, key, keylen); + MD5Final(tk, &ctx); + memset((void *) &ctx, 0, sizeof(ctx)); + key = tk; + local_keylen = MD5_LEN; + } + /* start out by storing key in pads */ + memcpy(hkey->hk_ipad, key, local_keylen); + memcpy(hkey->hk_opad, key, local_keylen); + + /* XOR key with hk_ipad and opad values */ + for (i = 0; i < HMAC_LEN; i++) { + hkey->hk_ipad[i] ^= HMAC_IPAD; + hkey->hk_opad[i] ^= HMAC_OPAD; + } + dkey->dk_key_size = local_keylen; + dkey->dk_KEY_struct = (void *) hkey; + return (1); +} + + +/************************************************************************** + * dst_hmac_md5_key_to_file_format + * Encodes an HMAC Key into the portable file format. + * Parameters + * hkey HMAC KEY structure + * buff output buffer + * buff_len size of output buffer + * Return + * 0 Failure - null input hkey + * -1 Failure - not enough space in output area + * N Success - Length of data returned in buff + */ + +static int +dst_hmac_md5_key_to_file_format(const DST_KEY *dkey, char *buff, + const int buff_len) +{ + char *bp; + int len, i, key_len; + u_char key[HMAC_LEN]; + HMAC_Key *hkey; + + if (dkey == NULL || dkey->dk_KEY_struct == NULL) + return (0); + /* + * Using snprintf() would be so much simpler here. + */ + if (buff == NULL || + buff_len <= (int)(strlen(key_file_fmt_str) + + strlen(KEY_FILE_FORMAT) + 4)) + return (-1); /*%< no OR not enough space in output area */ + hkey = (HMAC_Key *) dkey->dk_KEY_struct; + memset(buff, 0, buff_len); /*%< just in case */ + /* write file header */ + sprintf(buff, key_file_fmt_str, KEY_FILE_FORMAT, KEY_HMAC_MD5, "HMAC"); + + bp = buff + strlen(buff); + + memset(key, 0, HMAC_LEN); + for (i = 0; i < HMAC_LEN; i++) + key[i] = hkey->hk_ipad[i] ^ HMAC_IPAD; + for (i = HMAC_LEN - 1; i >= 0; i--) + if (key[i] != 0) + break; + key_len = i + 1; + + if (buff_len - (bp - buff) < 6) + return (-1); + strcat(bp, "Key: "); + bp += strlen("Key: "); + + len = b64_ntop(key, key_len, bp, buff_len - (bp - buff)); + if (len < 0) + return (-1); + bp += len; + if (buff_len - (bp - buff) < 2) + return (-1); + *(bp++) = '\n'; + *bp = '\0'; + + return (bp - buff); +} + + +/************************************************************************** + * dst_hmac_md5_key_from_file_format + * Converts contents of a key file into an HMAC key. + * Parameters + * hkey structure to put key into + * buff buffer containing the encoded key + * buff_len the length of the buffer + * Return + * n >= 0 Foot print of the key converted + * n < 0 Error in conversion + */ + +static int +dst_hmac_md5_key_from_file_format(DST_KEY *dkey, const char *buff, + const int buff_len) +{ + const char *p = buff, *eol; + u_char key[HMAC_LEN+1]; /* b64_pton needs more than 64 bytes do decode + * it should probably be fixed rather than doing + * this + */ + u_char *tmp; + int key_len, len; + + if (dkey == NULL) + return (-2); + if (buff == NULL || buff_len < 0) + return (-1); + + memset(key, 0, sizeof(key)); + + if (!dst_s_verify_str(&p, "Key: ")) + return (-3); + + eol = strchr(p, '\n'); + if (eol == NULL) + return (-4); + len = eol - p; + tmp = malloc(len + 2); + if (tmp == NULL) + return (-5); + memcpy(tmp, p, len); + *(tmp + len) = 0x0; + key_len = b64_pton((char *)tmp, key, HMAC_LEN+1); /*%< see above */ + SAFE_FREE2(tmp, len + 2); + + if (dst_buffer_to_hmac_md5(dkey, key, key_len) < 0) { + return (-6); + } + return (0); +} + +/*% + * dst_hmac_md5_to_dns_key() + * function to extract hmac key from DST_KEY structure + * intput: + * in_key: HMAC-MD5 key + * output: + * out_str: buffer to write ot + * out_len: size of output buffer + * returns: + * number of bytes written to output buffer + */ +static int +dst_hmac_md5_to_dns_key(const DST_KEY *in_key, u_char *out_str, + const int out_len) +{ + + HMAC_Key *hkey; + int i; + + if (in_key == NULL || in_key->dk_KEY_struct == NULL || + out_len <= in_key->dk_key_size || out_str == NULL) + return (-1); + + hkey = (HMAC_Key *) in_key->dk_KEY_struct; + for (i = 0; i < in_key->dk_key_size; i++) + out_str[i] = hkey->hk_ipad[i] ^ HMAC_IPAD; + return (i); +} + +/************************************************************************** + * dst_hmac_md5_compare_keys + * Compare two keys for equality. + * Return + * 0 The keys are equal + * NON-ZERO The keys are not equal + */ + +static int +dst_hmac_md5_compare_keys(const DST_KEY *key1, const DST_KEY *key2) +{ + HMAC_Key *hkey1 = (HMAC_Key *) key1->dk_KEY_struct; + HMAC_Key *hkey2 = (HMAC_Key *) key2->dk_KEY_struct; + return memcmp(hkey1->hk_ipad, hkey2->hk_ipad, HMAC_LEN); +} + +/************************************************************************** + * dst_hmac_md5_free_key_structure + * Frees all (none) dynamically allocated structures in hkey + */ + +static void * +dst_hmac_md5_free_key_structure(void *key) +{ + HMAC_Key *hkey = key; + SAFE_FREE(hkey); + return (NULL); +} + + +/*************************************************************************** + * dst_hmac_md5_generate_key + * Creates a HMAC key of size size with a maximum size of 63 bytes + * generating a HMAC key larger than 63 bytes makes no sense as that key + * is digested before use. + */ + +static int +dst_hmac_md5_generate_key(DST_KEY *key, const int nothing) +{ + (void)key; + (void)nothing; + return (-1); +} + +/*% + * dst_hmac_md5_init() Function to answer set up function pointers for HMAC + * related functions + */ +int +#ifdef SUNW_LIBMD5 +dst_md5_hmac_init() +#else +dst_hmac_md5_init() +#endif +{ + if (dst_t_func[KEY_HMAC_MD5] != NULL) + return (1); + dst_t_func[KEY_HMAC_MD5] = malloc(sizeof(struct dst_func)); + if (dst_t_func[KEY_HMAC_MD5] == NULL) + return (0); + memset(dst_t_func[KEY_HMAC_MD5], 0, sizeof(struct dst_func)); + dst_t_func[KEY_HMAC_MD5]->sign = dst_hmac_md5_sign; + dst_t_func[KEY_HMAC_MD5]->verify = dst_hmac_md5_verify; + dst_t_func[KEY_HMAC_MD5]->compare = dst_hmac_md5_compare_keys; + dst_t_func[KEY_HMAC_MD5]->generate = dst_hmac_md5_generate_key; + dst_t_func[KEY_HMAC_MD5]->destroy = dst_hmac_md5_free_key_structure; + dst_t_func[KEY_HMAC_MD5]->to_dns_key = dst_hmac_md5_to_dns_key; + dst_t_func[KEY_HMAC_MD5]->from_dns_key = dst_buffer_to_hmac_md5; + dst_t_func[KEY_HMAC_MD5]->to_file_fmt = dst_hmac_md5_key_to_file_format; + dst_t_func[KEY_HMAC_MD5]->from_file_fmt = dst_hmac_md5_key_from_file_format; + return (1); +} + +#else +#define dst_hmac_md5_init __dst_hmac_md5_init + +int +dst_hmac_md5_init(){ + return (0); +} +#endif + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/dst/md5.h b/contrib/bind-9.5.2/lib/bind/dst/md5.h new file mode 100644 index 0000000000..b1ed9e13fd --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/dst/md5.h @@ -0,0 +1,108 @@ +/* crypto/md/md5.h */ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_MD5_H +#define HEADER_MD5_H + +#ifndef HAVE_MD5 + +#ifdef __cplusplus +extern "C" { +#endif + +#define MD5_CBLOCK 64 +#define MD5_LBLOCK 16 +#define MD5_BLOCK 16 +#define MD5_LAST_BLOCK 56 +#define MD5_LENGTH_BLOCK 8 +#define MD5_DIGEST_LENGTH 16 + +typedef struct MD5state_st + { + unsigned long A,B,C,D; + unsigned long Nl,Nh; + unsigned long data[MD5_LBLOCK]; + int num; + } MD5_CTX; + +#ifndef NOPROTO +void MD5_Init(MD5_CTX *c); +void MD5_Update(MD5_CTX *c, const unsigned char *data, unsigned long len); +void MD5_Final(unsigned char *md, MD5_CTX *c); +unsigned char *MD5(unsigned char *d, unsigned long n, unsigned char *md); +#else +void MD5_Init(); +void MD5_Update(); +void MD5_Final(); +unsigned char *MD5(); +#endif + +/* to provide backward compatabilty to RSAREF calls ogud@tis.com 1997/11/14 */ +#define MD5Init(c) MD5_Init(c) +#define MD5Update(c,data, len) MD5_Update(c,data,len) +#define MD5Final(md, c) MD5_Final(md, c) +#ifdef __cplusplus +} +#endif + +#endif +#else +#include +#endif /* HAVE_MD5 */ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/dst/md5_dgst.c b/contrib/bind-9.5.2/lib/bind/dst/md5_dgst.c new file mode 100644 index 0000000000..76b0505760 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/dst/md5_dgst.c @@ -0,0 +1,374 @@ +/* crypto/md/md5_dgst.c */ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifdef USE_MD5 /*%< Added by ogud@tis.com 1998/1/26 */ +#include +#ifndef HAVE_MD5 +#include +#include "md5_locl.h" +#include + +const char *MD5_version="MD5 part of SSLeay 0.8.1 19-Jul-1997"; + +/*! \file + * \brief + * Implemented from RFC1321 The MD5 Message-Digest Algorithm + */ + +#define INIT_DATA_A (unsigned long)0x67452301L +#define INIT_DATA_B (unsigned long)0xefcdab89L +#define INIT_DATA_C (unsigned long)0x98badcfeL +#define INIT_DATA_D (unsigned long)0x10325476L + +#ifndef NOPROTO +static void md5_block(MD5_CTX *c, unsigned long *p); +#else +static void md5_block(); +#endif + +void MD5_Init(c) +MD5_CTX *c; + { + c->A=INIT_DATA_A; + c->B=INIT_DATA_B; + c->C=INIT_DATA_C; + c->D=INIT_DATA_D; + c->Nl=0; + c->Nh=0; + c->num=0; + } + +void MD5_Update(c, data, len) +MD5_CTX *c; +register const unsigned char *data; +unsigned long len; + { + register ULONG *p; + int sw,sc; + ULONG l; + + if (len == 0U) return; + + l=(c->Nl+(len<<3))&0xffffffffL; + /* 95-05-24 eay Fixed a bug with the overflow handling, thanks to + * Wei Dai for pointing it out. */ + if (l < c->Nl) /*%< overflow */ + c->Nh++; + c->Nh+=(len>>29); + c->Nl=l; + + if (c->num != 0) + { + p=c->data; + sw=c->num>>2; + sc=c->num&0x03; + + if ((c->num+len) >= (size_t)MD5_CBLOCK) + { + l= p[sw]; + p_c2l(data,l,sc); + p[sw++]=l; + for (; swnum); + + md5_block(c,p); + c->num=0; + /* drop through and do the rest */ + } + else + { + int ew,ec; + + c->num+=(int)len; + if ((sc+len) < 4U) /*%< ugly, add char's to a word */ + { + l= p[sw]; + p_c2l_p(data,l,sc,len); + p[sw]=l; + } + else + { + ew=(c->num>>2); + ec=(c->num&0x03); + l= p[sw]; + p_c2l(data,l,sc); + p[sw++]=l; + for (; sw < ew; sw++) + { c2l(data,l); p[sw]=l; } + if (ec) + { + c2l_p(data,l,ec); + p[sw]=l; + } + } + return; + } + } + /* we now can process the input data in blocks of MD5_CBLOCK + * chars and save the leftovers to c->data. */ + p=c->data; + while (len >= (size_t)MD5_CBLOCK) + { +#if defined(L_ENDIAN) || defined(B_ENDIAN) + memcpy(p,data,MD5_CBLOCK); + data+=MD5_CBLOCK; +#ifdef B_ENDIAN + for (sw=(MD5_LBLOCK/4); sw; sw--) + { + Endian_Reverse32(p[0]); + Endian_Reverse32(p[1]); + Endian_Reverse32(p[2]); + Endian_Reverse32(p[3]); + p+=4; + } +#endif +#else + for (sw=(MD5_LBLOCK/4); sw; sw--) + { + c2l(data,l); *(p++)=l; + c2l(data,l); *(p++)=l; + c2l(data,l); *(p++)=l; + c2l(data,l); *(p++)=l; + } +#endif + p=c->data; + md5_block(c,p); + len-=MD5_CBLOCK; + } + sc=(int)len; + c->num=sc; + if (sc) + { + sw=sc>>2; /*%< words to copy */ +#ifdef L_ENDIAN + p[sw]=0; + memcpy(p,data,sc); +#else + sc&=0x03; + for ( ; sw; sw--) + { c2l(data,l); *(p++)=l; } + c2l_p(data,l,sc); + *p=l; +#endif + } + } + +static void md5_block(c, X) +MD5_CTX *c; +register ULONG *X; + { + register ULONG A,B,C,D; + + A=c->A; + B=c->B; + C=c->C; + D=c->D; + + /* Round 0 */ + R0(A,B,C,D,X[ 0], 7,0xd76aa478L); + R0(D,A,B,C,X[ 1],12,0xe8c7b756L); + R0(C,D,A,B,X[ 2],17,0x242070dbL); + R0(B,C,D,A,X[ 3],22,0xc1bdceeeL); + R0(A,B,C,D,X[ 4], 7,0xf57c0fafL); + R0(D,A,B,C,X[ 5],12,0x4787c62aL); + R0(C,D,A,B,X[ 6],17,0xa8304613L); + R0(B,C,D,A,X[ 7],22,0xfd469501L); + R0(A,B,C,D,X[ 8], 7,0x698098d8L); + R0(D,A,B,C,X[ 9],12,0x8b44f7afL); + R0(C,D,A,B,X[10],17,0xffff5bb1L); + R0(B,C,D,A,X[11],22,0x895cd7beL); + R0(A,B,C,D,X[12], 7,0x6b901122L); + R0(D,A,B,C,X[13],12,0xfd987193L); + R0(C,D,A,B,X[14],17,0xa679438eL); + R0(B,C,D,A,X[15],22,0x49b40821L); + /* Round 1 */ + R1(A,B,C,D,X[ 1], 5,0xf61e2562L); + R1(D,A,B,C,X[ 6], 9,0xc040b340L); + R1(C,D,A,B,X[11],14,0x265e5a51L); + R1(B,C,D,A,X[ 0],20,0xe9b6c7aaL); + R1(A,B,C,D,X[ 5], 5,0xd62f105dL); + R1(D,A,B,C,X[10], 9,0x02441453L); + R1(C,D,A,B,X[15],14,0xd8a1e681L); + R1(B,C,D,A,X[ 4],20,0xe7d3fbc8L); + R1(A,B,C,D,X[ 9], 5,0x21e1cde6L); + R1(D,A,B,C,X[14], 9,0xc33707d6L); + R1(C,D,A,B,X[ 3],14,0xf4d50d87L); + R1(B,C,D,A,X[ 8],20,0x455a14edL); + R1(A,B,C,D,X[13], 5,0xa9e3e905L); + R1(D,A,B,C,X[ 2], 9,0xfcefa3f8L); + R1(C,D,A,B,X[ 7],14,0x676f02d9L); + R1(B,C,D,A,X[12],20,0x8d2a4c8aL); + /* Round 2 */ + R2(A,B,C,D,X[ 5], 4,0xfffa3942L); + R2(D,A,B,C,X[ 8],11,0x8771f681L); + R2(C,D,A,B,X[11],16,0x6d9d6122L); + R2(B,C,D,A,X[14],23,0xfde5380cL); + R2(A,B,C,D,X[ 1], 4,0xa4beea44L); + R2(D,A,B,C,X[ 4],11,0x4bdecfa9L); + R2(C,D,A,B,X[ 7],16,0xf6bb4b60L); + R2(B,C,D,A,X[10],23,0xbebfbc70L); + R2(A,B,C,D,X[13], 4,0x289b7ec6L); + R2(D,A,B,C,X[ 0],11,0xeaa127faL); + R2(C,D,A,B,X[ 3],16,0xd4ef3085L); + R2(B,C,D,A,X[ 6],23,0x04881d05L); + R2(A,B,C,D,X[ 9], 4,0xd9d4d039L); + R2(D,A,B,C,X[12],11,0xe6db99e5L); + R2(C,D,A,B,X[15],16,0x1fa27cf8L); + R2(B,C,D,A,X[ 2],23,0xc4ac5665L); + /* Round 3 */ + R3(A,B,C,D,X[ 0], 6,0xf4292244L); + R3(D,A,B,C,X[ 7],10,0x432aff97L); + R3(C,D,A,B,X[14],15,0xab9423a7L); + R3(B,C,D,A,X[ 5],21,0xfc93a039L); + R3(A,B,C,D,X[12], 6,0x655b59c3L); + R3(D,A,B,C,X[ 3],10,0x8f0ccc92L); + R3(C,D,A,B,X[10],15,0xffeff47dL); + R3(B,C,D,A,X[ 1],21,0x85845dd1L); + R3(A,B,C,D,X[ 8], 6,0x6fa87e4fL); + R3(D,A,B,C,X[15],10,0xfe2ce6e0L); + R3(C,D,A,B,X[ 6],15,0xa3014314L); + R3(B,C,D,A,X[13],21,0x4e0811a1L); + R3(A,B,C,D,X[ 4], 6,0xf7537e82L); + R3(D,A,B,C,X[11],10,0xbd3af235L); + R3(C,D,A,B,X[ 2],15,0x2ad7d2bbL); + R3(B,C,D,A,X[ 9],21,0xeb86d391L); + + c->A+=A&0xffffffffL; + c->B+=B&0xffffffffL; + c->C+=C&0xffffffffL; + c->D+=D&0xffffffffL; + } + +void MD5_Final(md, c) +unsigned char *md; +MD5_CTX *c; + { + register int i,j; + register ULONG l; + register ULONG *p; + static unsigned char end[4]={0x80,0x00,0x00,0x00}; + unsigned char *cp=end; + + /* c->num should definitly have room for at least one more byte. */ + p=c->data; + j=c->num; + i=j>>2; + + /* purify often complains about the following line as an + * Uninitialized Memory Read. While this can be true, the + * following p_c2l macro will reset l when that case is true. + * This is because j&0x03 contains the number of 'valid' bytes + * already in p[i]. If and only if j&0x03 == 0, the UMR will + * occur but this is also the only time p_c2l will do + * l= *(cp++) instead of l|= *(cp++) + * Many thanks to Alex Tang for pickup this + * 'potential bug' */ +#ifdef PURIFY + if ((j&0x03) == 0) p[i]=0; +#endif + l=p[i]; + p_c2l(cp,l,j&0x03); + p[i]=l; + i++; + /* i is the next 'undefined word' */ + if (c->num >= MD5_LAST_BLOCK) + { + for (; iNl; + p[MD5_LBLOCK-1]=c->Nh; + md5_block(c,p); + cp=md; + l=c->A; l2c(l,cp); + l=c->B; l2c(l,cp); + l=c->C; l2c(l,cp); + l=c->D; l2c(l,cp); + + /* clear stuff, md5_block may be leaving some stuff on the stack + * but I'm not worried :-) */ + c->num=0; +/* memset((char *)&c,0,sizeof(c));*/ + } + +#ifdef undef +int printit(l) +unsigned long *l; + { + int i,ii; + + for (i=0; i<2; i++) + { + for (ii=0; ii<8; ii++) + { + fprintf(stderr,"%08lx ",l[i*8+ii]); + } + fprintf(stderr,"\n"); + } + } +#endif +#endif /* HAVE_MD5 */ +#endif /* USE_MD5 */ diff --git a/contrib/bind-9.5.2/lib/bind/dst/md5_locl.h b/contrib/bind-9.5.2/lib/bind/dst/md5_locl.h new file mode 100644 index 0000000000..657fe8c3de --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/dst/md5_locl.h @@ -0,0 +1,193 @@ +/* crypto/md/md5_locl.h */ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include +#include +#include "md5.h" + +#define ULONG unsigned long +#define UCHAR unsigned char +#define UINT unsigned int + +#if defined(NOCONST) +#define const +#endif + +#undef c2l +#define c2l(c,l) (l = ((unsigned long)(*((c)++))) , \ + l|=(((unsigned long)(*((c)++)))<< 8), \ + l|=(((unsigned long)(*((c)++)))<<16), \ + l|=(((unsigned long)(*((c)++)))<<24)) + +#undef p_c2l +#define p_c2l(c,l,n) { \ + switch (n) { \ + case 0: l =((unsigned long)(*((c)++))); \ + case 1: l|=((unsigned long)(*((c)++)))<< 8; \ + case 2: l|=((unsigned long)(*((c)++)))<<16; \ + case 3: l|=((unsigned long)(*((c)++)))<<24; \ + } \ + } + +/* NOTE the pointer is not incremented at the end of this */ +#undef c2l_p +#define c2l_p(c,l,n) { \ + l=0; \ + (c)+=n; \ + switch (n) { \ + case 3: l =((unsigned long)(*(--(c))))<<16; \ + case 2: l|=((unsigned long)(*(--(c))))<< 8; \ + case 1: l|=((unsigned long)(*(--(c)))) ; \ + } \ + } + +#undef p_c2l_p +#define p_c2l_p(c,l,sc,len) { \ + switch (sc) \ + { \ + case 0: l =((unsigned long)(*((c)++))); \ + if (--len == 0U) break; \ + case 1: l|=((unsigned long)(*((c)++)))<< 8; \ + if (--len == 0U) break; \ + case 2: l|=((unsigned long)(*((c)++)))<<16; \ + } \ + } + +#undef l2c +#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16)&0xff), \ + *((c)++)=(unsigned char)(((l)>>24)&0xff)) + +/* NOTE - c is not incremented as per l2c */ +#undef l2cn +#define l2cn(l1,l2,c,n) { \ + c+=n; \ + switch (n) { \ + case 8: *(--(c))=(unsigned char)(((l2)>>24)&0xff); \ + case 7: *(--(c))=(unsigned char)(((l2)>>16)&0xff); \ + case 6: *(--(c))=(unsigned char)(((l2)>> 8)&0xff); \ + case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \ + case 4: *(--(c))=(unsigned char)(((l1)>>24)&0xff); \ + case 3: *(--(c))=(unsigned char)(((l1)>>16)&0xff); \ + case 2: *(--(c))=(unsigned char)(((l1)>> 8)&0xff); \ + case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \ + } \ + } + +/* A nice byte order reversal from Wei Dai */ +#if defined(WIN32) +/* 5 instructions with rotate instruction, else 9 */ +#define Endian_Reverse32(a) \ + { \ + unsigned long l=(a); \ + (a)=((ROTATE(l,8)&0x00FF00FF)|(ROTATE(l,24)&0xFF00FF00)); \ + } +#else +/* 6 instructions with rotate instruction, else 8 */ +#define Endian_Reverse32(a) \ + { \ + unsigned long l=(a); \ + l=(((l&0xFF00FF00)>>8L)|((l&0x00FF00FF)<<8L)); \ + (a)=ROTATE(l,16L); \ + } +#endif + +/*% +#define F(x,y,z) (((x) & (y)) | ((~(x)) & (z))) +#define G(x,y,z) (((x) & (z)) | ((y) & (~(z)))) +*/ + +/* As pointed out by Wei Dai , the above can be + * simplified to the code below. Wei attributes these optimisations + * to Peter Gutmann's SHS code, and he attributes it to Rich Schroeppel. + */ +#define F(x,y,z) ((((y) ^ (z)) & (x)) ^ (z)) +#define G(x,y,z) ((((x) ^ (y)) & (z)) ^ (y)) +#define H(x,y,z) ((x) ^ (y) ^ (z)) +#define I(x,y,z) (((x) | (~(z))) ^ (y)) + +#undef ROTATE +#if defined(WIN32) +#define ROTATE(a,n) _lrotl(a,n) +#else +#define ROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n)))) +#endif + + +#define R0(a,b,c,d,k,s,t) { \ + a+=((k)+(t)+F((b),(c),(d))); \ + a=ROTATE(a,s); \ + a+=b; };\ + +#define R1(a,b,c,d,k,s,t) { \ + a+=((k)+(t)+G((b),(c),(d))); \ + a=ROTATE(a,s); \ + a+=b; }; + +#define R2(a,b,c,d,k,s,t) { \ + a+=((k)+(t)+H((b),(c),(d))); \ + a=ROTATE(a,s); \ + a+=b; }; + +#define R3(a,b,c,d,k,s,t) { \ + a+=((k)+(t)+I((b),(c),(d))); \ + a=ROTATE(a,s); \ + a+=b; }; + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/dst/support.c b/contrib/bind-9.5.2/lib/bind/dst/support.c new file mode 100644 index 0000000000..31d6d7a039 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/dst/support.c @@ -0,0 +1,342 @@ +static const char rcsid[] = "$Header: /proj/cvs/prod/bind9/lib/bind/dst/Attic/support.c,v 1.6 2005/10/11 00:10:13 marka Exp $"; + + +/* + * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc. + * + * Permission to use, copy modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * TRUSTED INFORMATION SYSTEMS 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 THE SOFTWARE. + */ + +#include "port_before.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dst_internal.h" + +#include "port_after.h" + +/*% + * dst_s_verify_str() + * Validate that the input string(*str) is at the head of the input + * buffer(**buf). If so, move the buffer head pointer (*buf) to + * the first byte of data following the string(*str). + * Parameters + * buf Input buffer. + * str Input string. + * Return + * 0 *str is not the head of **buff + * 1 *str is the head of **buff, *buf is is advanced to + * the tail of **buf. + */ + +int +dst_s_verify_str(const char **buf, const char *str) +{ + int b, s; + if (*buf == NULL) /*%< error checks */ + return (0); + if (str == NULL || *str == '\0') + return (1); + + b = strlen(*buf); /*%< get length of strings */ + s = strlen(str); + if (s > b || strncmp(*buf, str, s)) /*%< check if same */ + return (0); /*%< not a match */ + (*buf) += s; /*%< advance pointer */ + return (1); +} + +/*% + * dst_s_calculate_bits + * Given a binary number represented in a u_char[], determine + * the number of significant bits used. + * Parameters + * str An input character string containing a binary number. + * max_bits The maximum possible significant bits. + * Return + * N The number of significant bits in str. + */ + +int +dst_s_calculate_bits(const u_char *str, const int max_bits) +{ + const u_char *p = str; + u_char i, j = 0x80; + int bits; + for (bits = max_bits; *p == 0x00 && bits > 0; p++) + bits -= 8; + for (i = *p; (i & j) != j; j >>= 1) + bits--; + return (bits); +} + +/*% + * calculates a checksum used in dst for an id. + * takes an array of bytes and a length. + * returns a 16 bit checksum. + */ +u_int16_t +dst_s_id_calc(const u_char *key, const int keysize) +{ + u_int32_t ac; + const u_char *kp = key; + int size = keysize; + + if (!key || (keysize <= 0)) + return (0xffffU); + + for (ac = 0; size > 1; size -= 2, kp += 2) + ac += ((*kp) << 8) + *(kp + 1); + + if (size > 0) + ac += ((*kp) << 8); + ac += (ac >> 16) & 0xffff; + + return (ac & 0xffff); +} + +/*% + * dst_s_dns_key_id() Function to calculate DNSSEC footprint from KEY record + * rdata + * Input: + * dns_key_rdata: the raw data in wire format + * rdata_len: the size of the input data + * Output: + * the key footprint/id calculated from the key data + */ +u_int16_t +dst_s_dns_key_id(const u_char *dns_key_rdata, const int rdata_len) +{ + if (!dns_key_rdata) + return 0; + + /* compute id */ + if (dns_key_rdata[3] == KEY_RSA) /*%< Algorithm RSA */ + return dst_s_get_int16((const u_char *) + &dns_key_rdata[rdata_len - 3]); + else if (dns_key_rdata[3] == KEY_HMAC_MD5) + /* compatibility */ + return 0; + else + /* compute a checksum on the key part of the key rr */ + return dst_s_id_calc(dns_key_rdata, rdata_len); +} + +/*% + * dst_s_get_int16 + * This routine extracts a 16 bit integer from a two byte character + * string. The character string is assumed to be in network byte + * order and may be unaligned. The number returned is in host order. + * Parameter + * buf A two byte character string. + * Return + * The converted integer value. + */ + +u_int16_t +dst_s_get_int16(const u_char *buf) +{ + register u_int16_t a = 0; + a = ((u_int16_t)(buf[0] << 8)) | ((u_int16_t)(buf[1])); + return (a); +} + +/*% + * dst_s_get_int32 + * This routine extracts a 32 bit integer from a four byte character + * string. The character string is assumed to be in network byte + * order and may be unaligned. The number returned is in host order. + * Parameter + * buf A four byte character string. + * Return + * The converted integer value. + */ + +u_int32_t +dst_s_get_int32(const u_char *buf) +{ + register u_int32_t a = 0; + a = ((u_int32_t)(buf[0] << 24)) | ((u_int32_t)(buf[1] << 16)) | + ((u_int32_t)(buf[2] << 8)) | ((u_int32_t)(buf[3])); + return (a); +} + +/*% + * dst_s_put_int16 + * Take a 16 bit integer and store the value in a two byte + * character string. The integer is assumed to be in network + * order and the string is returned in host order. + * + * Parameters + * buf Storage for a two byte character string. + * val 16 bit integer. + */ + +void +dst_s_put_int16(u_int8_t *buf, const u_int16_t val) +{ + buf[0] = (u_int8_t)(val >> 8); + buf[1] = (u_int8_t)(val); +} + +/*% + * dst_s_put_int32 + * Take a 32 bit integer and store the value in a four byte + * character string. The integer is assumed to be in network + * order and the string is returned in host order. + * + * Parameters + * buf Storage for a four byte character string. + * val 32 bit integer. + */ + +void +dst_s_put_int32(u_int8_t *buf, const u_int32_t val) +{ + buf[0] = (u_int8_t)(val >> 24); + buf[1] = (u_int8_t)(val >> 16); + buf[2] = (u_int8_t)(val >> 8); + buf[3] = (u_int8_t)(val); +} + +/*% + * dst_s_filename_length + * + * This function returns the number of bytes needed to hold the + * filename for a key file. '/', '\' and ':' are not allowed. + * form: K<keyname>+<alg>+<id>.<suffix> + * + * Returns 0 if the filename would contain either '\', '/' or ':' + */ +size_t +dst_s_filename_length(const char *name, const char *suffix) +{ + if (name == NULL) + return (0); + if (strrchr(name, '\\')) + return (0); + if (strrchr(name, '/')) + return (0); + if (strrchr(name, ':')) + return (0); + if (suffix == NULL) + return (0); + if (strrchr(suffix, '\\')) + return (0); + if (strrchr(suffix, '/')) + return (0); + if (strrchr(suffix, ':')) + return (0); + return (1 + strlen(name) + 6 + strlen(suffix)); +} + +/*% + * dst_s_build_filename () + * Builds a key filename from the key name, it's id, and a + * suffix. '\', '/' and ':' are not allowed. fA filename is of the + * form: K<keyname><id>.<suffix> + * form: K<keyname>+<alg>+<id>.<suffix> + * + * Returns -1 if the conversion fails: + * if the filename would be too long for space allotted + * if the filename would contain a '\', '/' or ':' + * Returns 0 on success + */ + +int +dst_s_build_filename(char *filename, const char *name, u_int16_t id, + int alg, const char *suffix, size_t filename_length) +{ + u_int32_t my_id; + if (filename == NULL) + return (-1); + memset(filename, 0, filename_length); + if (name == NULL) + return (-1); + if (suffix == NULL) + return (-1); + if (filename_length < 1 + strlen(name) + 4 + 6 + 1 + strlen(suffix)) + return (-1); + my_id = id; + sprintf(filename, "K%s+%03d+%05d.%s", name, alg, my_id, + (const char *) suffix); + if (strrchr(filename, '/')) + return (-1); + if (strrchr(filename, '\\')) + return (-1); + if (strrchr(filename, ':')) + return (-1); + return (0); +} + +/*% + * dst_s_fopen () + * Open a file in the dst_path directory. If perm is specified, the + * file is checked for existence first, and not opened if it exists. + * Parameters + * filename File to open + * mode Mode to open the file (passed directly to fopen) + * perm File permission, if creating a new file. + * Returns + * NULL Failure + * NON-NULL (FILE *) of opened file. + */ +FILE * +dst_s_fopen(const char *filename, const char *mode, int perm) +{ + FILE *fp; + char pathname[PATH_MAX]; + + if (strlen(filename) + strlen(dst_path) >= sizeof(pathname)) + return (NULL); + + if (*dst_path != '\0') { + strcpy(pathname, dst_path); + strcat(pathname, filename); + } else + strcpy(pathname, filename); + + fp = fopen(pathname, mode); + if (perm) + chmod(pathname, perm); + return (fp); +} + +void +dst_s_dump(const int mode, const u_char *data, const int size, + const char *msg) +{ + UNUSED(data); + + if (size > 0) { +#ifdef LONG_TEST + static u_char scratch[1000]; + int n ; + n = b64_ntop(data, scratch, size, sizeof(scratch)); + printf("%s: %x %d %s\n", msg, mode, n, scratch); +#else + printf("%s,%x %d\n", msg, mode, size); +#endif + } +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/include/arpa/inet.h b/contrib/bind-9.5.2/lib/bind/include/arpa/inet.h new file mode 100644 index 0000000000..d40ccfce00 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/arpa/inet.h @@ -0,0 +1,126 @@ +/* + * ++Copyright++ 1983, 1993 + * - + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION 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. + * - + * --Copyright-- + */ + +/*% + * @(#)inet.h 8.1 (Berkeley) 6/2/93 + * $Id: inet.h,v 1.3 2005/04/27 04:56:16 sra Exp $ + */ + +#ifndef _INET_H_ +#define _INET_H_ + +/* External definitions for functions in inet(3) */ + +#include +#if (!defined(BSD)) || (BSD < 199306) +# include +#else +# include +#endif +#include + +#define inet_addr __inet_addr +#define inet_aton __inet_aton +#define inet_lnaof __inet_lnaof +#define inet_makeaddr __inet_makeaddr +#define inet_neta __inet_neta +#define inet_netof __inet_netof +#define inet_network __inet_network +#define inet_net_ntop __inet_net_ntop +#define inet_net_pton __inet_net_pton +#define inet_cidr_ntop __inet_cidr_ntop +#define inet_cidr_pton __inet_cidr_pton +#define inet_ntoa __inet_ntoa +#define inet_pton __inet_pton +#define inet_ntop __inet_ntop +#define inet_nsap_addr __inet_nsap_addr +#define inet_nsap_ntoa __inet_nsap_ntoa + +__BEGIN_DECLS +unsigned long inet_addr __P((const char *)); +int inet_aton __P((const char *, struct in_addr *)); +unsigned long inet_lnaof __P((struct in_addr)); +struct in_addr inet_makeaddr __P((u_long , u_long)); +char * inet_neta __P((u_long, char *, size_t)); +unsigned long inet_netof __P((struct in_addr)); +unsigned long inet_network __P((const char *)); +char *inet_net_ntop __P((int, const void *, int, char *, size_t)); +int inet_net_pton __P((int, const char *, void *, size_t)); +char *inet_cidr_ntop __P((int, const void *, int, char *, size_t)); +int inet_cidr_pton __P((int, const char *, void *, int *)); +/*const*/ char *inet_ntoa __P((struct in_addr)); +int inet_pton __P((int, const char *, void *)); +const char *inet_ntop __P((int, const void *, char *, size_t)); +u_int inet_nsap_addr __P((const char *, u_char *, int)); +char *inet_nsap_ntoa __P((int, const u_char *, char *)); +__END_DECLS + +#if defined(__hpux) && defined(_XOPEN_SOURCE_EXTENDED) +/* + * Macros for number representation conversion. + * + * netinet/in.h is another location for these macros + */ +#ifndef ntohl +#define ntohl(x) (x) +#define ntohs(x) (x) +#define htonl(x) (x) +#define htons(x) (x) +#endif +#endif + +#endif /* !_INET_H_ */ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/include/arpa/nameser.h b/contrib/bind-9.5.2/lib/bind/include/arpa/nameser.h new file mode 100644 index 0000000000..d1cbf4283a --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/arpa/nameser.h @@ -0,0 +1,575 @@ +/* + * Copyright (c) 1983, 1989, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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: nameser.h,v 1.8.672.1 2008/04/03 02:12:21 marka Exp $ + */ + +#ifndef _ARPA_NAMESER_H_ +#define _ARPA_NAMESER_H_ + +/*! \file */ + +#define BIND_4_COMPAT + +#include +#if (!defined(BSD)) || (BSD < 199306) +# include +#else +# include +#endif +#include + +/*% + * Revision information. This is the release date in YYYYMMDD format. + * It can change every day so the right thing to do with it is use it + * in preprocessor commands such as "#if (__NAMESER > 19931104)". Do not + * compare for equality; rather, use it to determine whether your libbind.a + * contains a new enough lib/nameser/ to support the feature you need. + */ + +#define __NAMESER 19991006 /*%< New interface version stamp. */ +/* + * Define constants based on RFC0883, RFC1034, RFC 1035 + */ +#define NS_PACKETSZ 512 /*%< default UDP packet size */ +#define NS_MAXDNAME 1025 /*%< maximum domain name */ +#define NS_MAXMSG 65535 /*%< maximum message size */ +#define NS_MAXCDNAME 255 /*%< maximum compressed domain name */ +#define NS_MAXLABEL 63 /*%< maximum length of domain label */ +#define NS_HFIXEDSZ 12 /*%< #/bytes of fixed data in header */ +#define NS_QFIXEDSZ 4 /*%< #/bytes of fixed data in query */ +#define NS_RRFIXEDSZ 10 /*%< #/bytes of fixed data in r record */ +#define NS_INT32SZ 4 /*%< #/bytes of data in a u_int32_t */ +#define NS_INT16SZ 2 /*%< #/bytes of data in a u_int16_t */ +#define NS_INT8SZ 1 /*%< #/bytes of data in a u_int8_t */ +#define NS_INADDRSZ 4 /*%< IPv4 T_A */ +#define NS_IN6ADDRSZ 16 /*%< IPv6 T_AAAA */ +#define NS_CMPRSFLGS 0xc0 /*%< Flag bits indicating name compression. */ +#define NS_DEFAULTPORT 53 /*%< For both TCP and UDP. */ +/* + * These can be expanded with synonyms, just keep ns_parse.c:ns_parserecord() + * in synch with it. + */ +typedef enum __ns_sect { + ns_s_qd = 0, /*%< Query: Question. */ + ns_s_zn = 0, /*%< Update: Zone. */ + ns_s_an = 1, /*%< Query: Answer. */ + ns_s_pr = 1, /*%< Update: Prerequisites. */ + ns_s_ns = 2, /*%< Query: Name servers. */ + ns_s_ud = 2, /*%< Update: Update. */ + ns_s_ar = 3, /*%< Query|Update: Additional records. */ + ns_s_max = 4 +} ns_sect; + +/*% + * This is a message handle. It is caller allocated and has no dynamic data. + * This structure is intended to be opaque to all but ns_parse.c, thus the + * leading _'s on the member names. Use the accessor functions, not the _'s. + */ +typedef struct __ns_msg { + const u_char *_msg, *_eom; + u_int16_t _id, _flags, _counts[ns_s_max]; + const u_char *_sections[ns_s_max]; + ns_sect _sect; + int _rrnum; + const u_char *_msg_ptr; +} ns_msg; + +/* Private data structure - do not use from outside library. */ +struct _ns_flagdata { int mask, shift; }; +extern struct _ns_flagdata _ns_flagdata[]; + +/* Accessor macros - this is part of the public interface. */ + +#define ns_msg_id(handle) ((handle)._id + 0) +#define ns_msg_base(handle) ((handle)._msg + 0) +#define ns_msg_end(handle) ((handle)._eom + 0) +#define ns_msg_size(handle) ((handle)._eom - (handle)._msg) +#define ns_msg_count(handle, section) ((handle)._counts[section] + 0) + +/*% + * This is a parsed record. It is caller allocated and has no dynamic data. + */ +typedef struct __ns_rr { + char name[NS_MAXDNAME]; + u_int16_t type; + u_int16_t rr_class; + u_int32_t ttl; + u_int16_t rdlength; + const u_char * rdata; +} ns_rr; + +/* Accessor macros - this is part of the public interface. */ +#define ns_rr_name(rr) (((rr).name[0] != '\0') ? (rr).name : ".") +#define ns_rr_type(rr) ((ns_type)((rr).type + 0)) +#define ns_rr_class(rr) ((ns_class)((rr).rr_class + 0)) +#define ns_rr_ttl(rr) ((rr).ttl + 0) +#define ns_rr_rdlen(rr) ((rr).rdlength + 0) +#define ns_rr_rdata(rr) ((rr).rdata + 0) + +/*% + * These don't have to be in the same order as in the packet flags word, + * and they can even overlap in some cases, but they will need to be kept + * in synch with ns_parse.c:ns_flagdata[]. + */ +typedef enum __ns_flag { + ns_f_qr, /*%< Question/Response. */ + ns_f_opcode, /*%< Operation code. */ + ns_f_aa, /*%< Authoritative Answer. */ + ns_f_tc, /*%< Truncation occurred. */ + ns_f_rd, /*%< Recursion Desired. */ + ns_f_ra, /*%< Recursion Available. */ + ns_f_z, /*%< MBZ. */ + ns_f_ad, /*%< Authentic Data (DNSSEC). */ + ns_f_cd, /*%< Checking Disabled (DNSSEC). */ + ns_f_rcode, /*%< Response code. */ + ns_f_max +} ns_flag; + +/*% + * Currently defined opcodes. + */ +typedef enum __ns_opcode { + ns_o_query = 0, /*%< Standard query. */ + ns_o_iquery = 1, /*%< Inverse query (deprecated/unsupported). */ + ns_o_status = 2, /*%< Name server status query (unsupported). */ + /* Opcode 3 is undefined/reserved. */ + ns_o_notify = 4, /*%< Zone change notification. */ + ns_o_update = 5, /*%< Zone update message. */ + ns_o_max = 6 +} ns_opcode; + +/*% + * Currently defined response codes. + */ +typedef enum __ns_rcode { + ns_r_noerror = 0, /*%< No error occurred. */ + ns_r_formerr = 1, /*%< Format error. */ + ns_r_servfail = 2, /*%< Server failure. */ + ns_r_nxdomain = 3, /*%< Name error. */ + ns_r_notimpl = 4, /*%< Unimplemented. */ + ns_r_refused = 5, /*%< Operation refused. */ + /* these are for BIND_UPDATE */ + ns_r_yxdomain = 6, /*%< Name exists */ + ns_r_yxrrset = 7, /*%< RRset exists */ + ns_r_nxrrset = 8, /*%< RRset does not exist */ + ns_r_notauth = 9, /*%< Not authoritative for zone */ + ns_r_notzone = 10, /*%< Zone of record different from zone section */ + ns_r_max = 11, + /* The following are EDNS extended rcodes */ + ns_r_badvers = 16, + /* The following are TSIG errors */ + ns_r_badsig = 16, + ns_r_badkey = 17, + ns_r_badtime = 18 +} ns_rcode; + +/* BIND_UPDATE */ +typedef enum __ns_update_operation { + ns_uop_delete = 0, + ns_uop_add = 1, + ns_uop_max = 2 +} ns_update_operation; + +/*% + * This structure is used for TSIG authenticated messages + */ +struct ns_tsig_key { + char name[NS_MAXDNAME], alg[NS_MAXDNAME]; + unsigned char *data; + int len; +}; +typedef struct ns_tsig_key ns_tsig_key; + +/*% + * This structure is used for TSIG authenticated TCP messages + */ +struct ns_tcp_tsig_state { + int counter; + struct dst_key *key; + void *ctx; + unsigned char sig[NS_PACKETSZ]; + int siglen; +}; +typedef struct ns_tcp_tsig_state ns_tcp_tsig_state; + +#define NS_TSIG_FUDGE 300 +#define NS_TSIG_TCP_COUNT 100 +#define NS_TSIG_ALG_HMAC_MD5 "HMAC-MD5.SIG-ALG.REG.INT" + +#define NS_TSIG_ERROR_NO_TSIG -10 +#define NS_TSIG_ERROR_NO_SPACE -11 +#define NS_TSIG_ERROR_FORMERR -12 + +/*% + * Currently defined type values for resources and queries. + */ +typedef enum __ns_type { + ns_t_invalid = 0, /*%< Cookie. */ + ns_t_a = 1, /*%< Host address. */ + ns_t_ns = 2, /*%< Authoritative server. */ + ns_t_md = 3, /*%< Mail destination. */ + ns_t_mf = 4, /*%< Mail forwarder. */ + ns_t_cname = 5, /*%< Canonical name. */ + ns_t_soa = 6, /*%< Start of authority zone. */ + ns_t_mb = 7, /*%< Mailbox domain name. */ + ns_t_mg = 8, /*%< Mail group member. */ + ns_t_mr = 9, /*%< Mail rename name. */ + ns_t_null = 10, /*%< Null resource record. */ + ns_t_wks = 11, /*%< Well known service. */ + ns_t_ptr = 12, /*%< Domain name pointer. */ + ns_t_hinfo = 13, /*%< Host information. */ + ns_t_minfo = 14, /*%< Mailbox information. */ + ns_t_mx = 15, /*%< Mail routing information. */ + ns_t_txt = 16, /*%< Text strings. */ + ns_t_rp = 17, /*%< Responsible person. */ + ns_t_afsdb = 18, /*%< AFS cell database. */ + ns_t_x25 = 19, /*%< X_25 calling address. */ + ns_t_isdn = 20, /*%< ISDN calling address. */ + ns_t_rt = 21, /*%< Router. */ + ns_t_nsap = 22, /*%< NSAP address. */ + ns_t_nsap_ptr = 23, /*%< Reverse NSAP lookup (deprecated). */ + ns_t_sig = 24, /*%< Security signature. */ + ns_t_key = 25, /*%< Security key. */ + ns_t_px = 26, /*%< X.400 mail mapping. */ + ns_t_gpos = 27, /*%< Geographical position (withdrawn). */ + ns_t_aaaa = 28, /*%< Ip6 Address. */ + ns_t_loc = 29, /*%< Location Information. */ + ns_t_nxt = 30, /*%< Next domain (security). */ + ns_t_eid = 31, /*%< Endpoint identifier. */ + ns_t_nimloc = 32, /*%< Nimrod Locator. */ + ns_t_srv = 33, /*%< Server Selection. */ + ns_t_atma = 34, /*%< ATM Address */ + ns_t_naptr = 35, /*%< Naming Authority PoinTeR */ + ns_t_kx = 36, /*%< Key Exchange */ + ns_t_cert = 37, /*%< Certification record */ + ns_t_a6 = 38, /*%< IPv6 address (deprecates AAAA) */ + ns_t_dname = 39, /*%< Non-terminal DNAME (for IPv6) */ + ns_t_sink = 40, /*%< Kitchen sink (experimentatl) */ + ns_t_opt = 41, /*%< EDNS0 option (meta-RR) */ + ns_t_apl = 42, /*%< Address prefix list (RFC3123) */ + ns_t_tkey = 249, /*%< Transaction key */ + ns_t_tsig = 250, /*%< Transaction signature. */ + ns_t_ixfr = 251, /*%< Incremental zone transfer. */ + ns_t_axfr = 252, /*%< Transfer zone of authority. */ + ns_t_mailb = 253, /*%< Transfer mailbox records. */ + ns_t_maila = 254, /*%< Transfer mail agent records. */ + ns_t_any = 255, /*%< Wildcard match. */ + ns_t_zxfr = 256, /*%< BIND-specific, nonstandard. */ + ns_t_max = 65536 +} ns_type; + +/* Exclusively a QTYPE? (not also an RTYPE) */ +#define ns_t_qt_p(t) (ns_t_xfr_p(t) || (t) == ns_t_any || \ + (t) == ns_t_mailb || (t) == ns_t_maila) +/* Some kind of meta-RR? (not a QTYPE, but also not an RTYPE) */ +#define ns_t_mrr_p(t) ((t) == ns_t_tsig || (t) == ns_t_opt) +/* Exclusively an RTYPE? (not also a QTYPE or a meta-RR) */ +#define ns_t_rr_p(t) (!ns_t_qt_p(t) && !ns_t_mrr_p(t)) +#define ns_t_udp_p(t) ((t) != ns_t_axfr && (t) != ns_t_zxfr) +#define ns_t_xfr_p(t) ((t) == ns_t_axfr || (t) == ns_t_ixfr || \ + (t) == ns_t_zxfr) + +/*% + * Values for class field + */ +typedef enum __ns_class { + ns_c_invalid = 0, /*%< Cookie. */ + ns_c_in = 1, /*%< Internet. */ + ns_c_2 = 2, /*%< unallocated/unsupported. */ + ns_c_chaos = 3, /*%< MIT Chaos-net. */ + ns_c_hs = 4, /*%< MIT Hesiod. */ + /* Query class values which do not appear in resource records */ + ns_c_none = 254, /*%< for prereq. sections in update requests */ + ns_c_any = 255, /*%< Wildcard match. */ + ns_c_max = 65536 +} ns_class; + +/* DNSSEC constants. */ + +typedef enum __ns_key_types { + ns_kt_rsa = 1, /*%< key type RSA/MD5 */ + ns_kt_dh = 2, /*%< Diffie Hellman */ + ns_kt_dsa = 3, /*%< Digital Signature Standard (MANDATORY) */ + ns_kt_private = 254 /*%< Private key type starts with OID */ +} ns_key_types; + +typedef enum __ns_cert_types { + cert_t_pkix = 1, /*%< PKIX (X.509v3) */ + cert_t_spki = 2, /*%< SPKI */ + cert_t_pgp = 3, /*%< PGP */ + cert_t_url = 253, /*%< URL private type */ + cert_t_oid = 254 /*%< OID private type */ +} ns_cert_types; + +/* Flags field of the KEY RR rdata. */ +#define NS_KEY_TYPEMASK 0xC000 /*%< Mask for "type" bits */ +#define NS_KEY_TYPE_AUTH_CONF 0x0000 /*%< Key usable for both */ +#define NS_KEY_TYPE_CONF_ONLY 0x8000 /*%< Key usable for confidentiality */ +#define NS_KEY_TYPE_AUTH_ONLY 0x4000 /*%< Key usable for authentication */ +#define NS_KEY_TYPE_NO_KEY 0xC000 /*%< No key usable for either; no key */ +/* The type bits can also be interpreted independently, as single bits: */ +#define NS_KEY_NO_AUTH 0x8000 /*%< Key unusable for authentication */ +#define NS_KEY_NO_CONF 0x4000 /*%< Key unusable for confidentiality */ +#define NS_KEY_RESERVED2 0x2000 /* Security is *mandatory* if bit=0 */ +#define NS_KEY_EXTENDED_FLAGS 0x1000 /*%< reserved - must be zero */ +#define NS_KEY_RESERVED4 0x0800 /*%< reserved - must be zero */ +#define NS_KEY_RESERVED5 0x0400 /*%< reserved - must be zero */ +#define NS_KEY_NAME_TYPE 0x0300 /*%< these bits determine the type */ +#define NS_KEY_NAME_USER 0x0000 /*%< key is assoc. with user */ +#define NS_KEY_NAME_ENTITY 0x0200 /*%< key is assoc. with entity eg host */ +#define NS_KEY_NAME_ZONE 0x0100 /*%< key is zone key */ +#define NS_KEY_NAME_RESERVED 0x0300 /*%< reserved meaning */ +#define NS_KEY_RESERVED8 0x0080 /*%< reserved - must be zero */ +#define NS_KEY_RESERVED9 0x0040 /*%< reserved - must be zero */ +#define NS_KEY_RESERVED10 0x0020 /*%< reserved - must be zero */ +#define NS_KEY_RESERVED11 0x0010 /*%< reserved - must be zero */ +#define NS_KEY_SIGNATORYMASK 0x000F /*%< key can sign RR's of same name */ +#define NS_KEY_RESERVED_BITMASK ( NS_KEY_RESERVED2 | \ + NS_KEY_RESERVED4 | \ + NS_KEY_RESERVED5 | \ + NS_KEY_RESERVED8 | \ + NS_KEY_RESERVED9 | \ + NS_KEY_RESERVED10 | \ + NS_KEY_RESERVED11 ) +#define NS_KEY_RESERVED_BITMASK2 0xFFFF /*%< no bits defined here */ +/* The Algorithm field of the KEY and SIG RR's is an integer, {1..254} */ +#define NS_ALG_MD5RSA 1 /*%< MD5 with RSA */ +#define NS_ALG_DH 2 /*%< Diffie Hellman KEY */ +#define NS_ALG_DSA 3 /*%< DSA KEY */ +#define NS_ALG_DSS NS_ALG_DSA +#define NS_ALG_EXPIRE_ONLY 253 /*%< No alg, no security */ +#define NS_ALG_PRIVATE_OID 254 /*%< Key begins with OID giving alg */ +/* Protocol values */ +/* value 0 is reserved */ +#define NS_KEY_PROT_TLS 1 +#define NS_KEY_PROT_EMAIL 2 +#define NS_KEY_PROT_DNSSEC 3 +#define NS_KEY_PROT_IPSEC 4 +#define NS_KEY_PROT_ANY 255 + +/* Signatures */ +#define NS_MD5RSA_MIN_BITS 512 /*%< Size of a mod or exp in bits */ +#define NS_MD5RSA_MAX_BITS 4096 + /* Total of binary mod and exp */ +#define NS_MD5RSA_MAX_BYTES ((NS_MD5RSA_MAX_BITS+7/8)*2+3) + /* Max length of text sig block */ +#define NS_MD5RSA_MAX_BASE64 (((NS_MD5RSA_MAX_BYTES+2)/3)*4) +#define NS_MD5RSA_MIN_SIZE ((NS_MD5RSA_MIN_BITS+7)/8) +#define NS_MD5RSA_MAX_SIZE ((NS_MD5RSA_MAX_BITS+7)/8) + +#define NS_DSA_SIG_SIZE 41 +#define NS_DSA_MIN_SIZE 213 +#define NS_DSA_MAX_BYTES 405 + +/* Offsets into SIG record rdata to find various values */ +#define NS_SIG_TYPE 0 /*%< Type flags */ +#define NS_SIG_ALG 2 /*%< Algorithm */ +#define NS_SIG_LABELS 3 /*%< How many labels in name */ +#define NS_SIG_OTTL 4 /*%< Original TTL */ +#define NS_SIG_EXPIR 8 /*%< Expiration time */ +#define NS_SIG_SIGNED 12 /*%< Signature time */ +#define NS_SIG_FOOT 16 /*%< Key footprint */ +#define NS_SIG_SIGNER 18 /*%< Domain name of who signed it */ +/* How RR types are represented as bit-flags in NXT records */ +#define NS_NXT_BITS 8 +#define NS_NXT_BIT_SET( n,p) (p[(n)/NS_NXT_BITS] |= (0x80>>((n)%NS_NXT_BITS))) +#define NS_NXT_BIT_CLEAR(n,p) (p[(n)/NS_NXT_BITS] &= ~(0x80>>((n)%NS_NXT_BITS))) +#define NS_NXT_BIT_ISSET(n,p) (p[(n)/NS_NXT_BITS] & (0x80>>((n)%NS_NXT_BITS))) +#define NS_NXT_MAX 127 + +/*% + * EDNS0 extended flags and option codes, host order. + */ +#define NS_OPT_DNSSEC_OK 0x8000U +#define NS_OPT_NSID 3 + +/*% + * Inline versions of get/put short/long. Pointer is advanced. + */ +#define NS_GET16(s, cp) do { \ + register const u_char *t_cp = (const u_char *)(cp); \ + (s) = ((u_int16_t)t_cp[0] << 8) \ + | ((u_int16_t)t_cp[1]) \ + ; \ + (cp) += NS_INT16SZ; \ +} while (0) + +#define NS_GET32(l, cp) do { \ + register const u_char *t_cp = (const u_char *)(cp); \ + (l) = ((u_int32_t)t_cp[0] << 24) \ + | ((u_int32_t)t_cp[1] << 16) \ + | ((u_int32_t)t_cp[2] << 8) \ + | ((u_int32_t)t_cp[3]) \ + ; \ + (cp) += NS_INT32SZ; \ +} while (0) + +#define NS_PUT16(s, cp) do { \ + register u_int16_t t_s = (u_int16_t)(s); \ + register u_char *t_cp = (u_char *)(cp); \ + *t_cp++ = t_s >> 8; \ + *t_cp = t_s; \ + (cp) += NS_INT16SZ; \ +} while (0) + +#define NS_PUT32(l, cp) do { \ + register u_int32_t t_l = (u_int32_t)(l); \ + register u_char *t_cp = (u_char *)(cp); \ + *t_cp++ = t_l >> 24; \ + *t_cp++ = t_l >> 16; \ + *t_cp++ = t_l >> 8; \ + *t_cp = t_l; \ + (cp) += NS_INT32SZ; \ +} while (0) + +/*% + * ANSI C identifier hiding for bind's lib/nameser. + */ +#define ns_msg_getflag __ns_msg_getflag +#define ns_get16 __ns_get16 +#define ns_get32 __ns_get32 +#define ns_put16 __ns_put16 +#define ns_put32 __ns_put32 +#define ns_initparse __ns_initparse +#define ns_skiprr __ns_skiprr +#define ns_parserr __ns_parserr +#define ns_sprintrr __ns_sprintrr +#define ns_sprintrrf __ns_sprintrrf +#define ns_format_ttl __ns_format_ttl +#define ns_parse_ttl __ns_parse_ttl +#define ns_datetosecs __ns_datetosecs +#define ns_name_ntol __ns_name_ntol +#define ns_name_ntop __ns_name_ntop +#define ns_name_pton __ns_name_pton +#define ns_name_unpack __ns_name_unpack +#define ns_name_pack __ns_name_pack +#define ns_name_compress __ns_name_compress +#define ns_name_uncompress __ns_name_uncompress +#define ns_name_skip __ns_name_skip +#define ns_name_rollback __ns_name_rollback +#define ns_sign __ns_sign +#define ns_sign2 __ns_sign2 +#define ns_sign_tcp __ns_sign_tcp +#define ns_sign_tcp2 __ns_sign_tcp2 +#define ns_sign_tcp_init __ns_sign_tcp_init +#define ns_find_tsig __ns_find_tsig +#define ns_verify __ns_verify +#define ns_verify_tcp __ns_verify_tcp +#define ns_verify_tcp_init __ns_verify_tcp_init +#define ns_samedomain __ns_samedomain +#define ns_subdomain __ns_subdomain +#define ns_makecanon __ns_makecanon +#define ns_samename __ns_samename + +__BEGIN_DECLS +int ns_msg_getflag __P((ns_msg, int)); +u_int ns_get16 __P((const u_char *)); +u_long ns_get32 __P((const u_char *)); +void ns_put16 __P((u_int, u_char *)); +void ns_put32 __P((u_long, u_char *)); +int ns_initparse __P((const u_char *, int, ns_msg *)); +int ns_skiprr __P((const u_char *, const u_char *, ns_sect, int)); +int ns_parserr __P((ns_msg *, ns_sect, int, ns_rr *)); +int ns_sprintrr __P((const ns_msg *, const ns_rr *, + const char *, const char *, char *, size_t)); +int ns_sprintrrf __P((const u_char *, size_t, const char *, + ns_class, ns_type, u_long, const u_char *, + size_t, const char *, const char *, + char *, size_t)); +int ns_format_ttl __P((u_long, char *, size_t)); +int ns_parse_ttl __P((const char *, u_long *)); +u_int32_t ns_datetosecs __P((const char *cp, int *errp)); +int ns_name_ntol __P((const u_char *, u_char *, size_t)); +int ns_name_ntop __P((const u_char *, char *, size_t)); +int ns_name_pton __P((const char *, u_char *, size_t)); +int ns_name_unpack __P((const u_char *, const u_char *, + const u_char *, u_char *, size_t)); +int ns_name_pack __P((const u_char *, u_char *, int, + const u_char **, const u_char **)); +int ns_name_uncompress __P((const u_char *, const u_char *, + const u_char *, char *, size_t)); +int ns_name_compress __P((const char *, u_char *, size_t, + const u_char **, const u_char **)); +int ns_name_skip __P((const u_char **, const u_char *)); +void ns_name_rollback __P((const u_char *, const u_char **, + const u_char **)); +int ns_sign __P((u_char *, int *, int, int, void *, + const u_char *, int, u_char *, int *, time_t)); +int ns_sign2 __P((u_char *, int *, int, int, void *, + const u_char *, int, u_char *, int *, time_t, + u_char **, u_char **)); +int ns_sign_tcp __P((u_char *, int *, int, int, + ns_tcp_tsig_state *, int)); +int ns_sign_tcp2 __P((u_char *, int *, int, int, + ns_tcp_tsig_state *, int, + u_char **, u_char **)); +int ns_sign_tcp_init __P((void *, const u_char *, int, + ns_tcp_tsig_state *)); +u_char *ns_find_tsig __P((u_char *, u_char *)); +int ns_verify __P((u_char *, int *, void *, + const u_char *, int, u_char *, int *, + time_t *, int)); +int ns_verify_tcp __P((u_char *, int *, ns_tcp_tsig_state *, int)); +int ns_verify_tcp_init __P((void *, const u_char *, int, + ns_tcp_tsig_state *)); +int ns_samedomain __P((const char *, const char *)); +int ns_subdomain __P((const char *, const char *)); +int ns_makecanon __P((const char *, char *, size_t)); +int ns_samename __P((const char *, const char *)); +__END_DECLS + +#ifdef BIND_4_COMPAT +#include +#endif + +#endif /* !_ARPA_NAMESER_H_ */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/include/arpa/nameser_compat.h b/contrib/bind-9.5.2/lib/bind/include/arpa/nameser_compat.h new file mode 100644 index 0000000000..5c6988288b --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/arpa/nameser_compat.h @@ -0,0 +1,232 @@ +/* Copyright (c) 1983, 1989 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/*% + * from nameser.h 8.1 (Berkeley) 6/2/93 + * $Id: nameser_compat.h,v 1.8 2006/05/19 02:33:40 marka Exp $ + */ + +#ifndef _ARPA_NAMESER_COMPAT_ +#define _ARPA_NAMESER_COMPAT_ + +#define __BIND 19950621 /*%< (DEAD) interface version stamp. */ +#ifndef BYTE_ORDER +#if (BSD >= 199103) +# include +#else +#ifdef __linux +# include +#else +#define LITTLE_ENDIAN 1234 /*%< least-significant byte first (vax, pc) */ +#define BIG_ENDIAN 4321 /*%< most-significant byte first (IBM, net) */ +#define PDP_ENDIAN 3412 /*%< LSB first in word, MSW first in long (pdp) */ +#if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \ + defined(__i386__) || defined(__i386) || defined(__amd64__) || \ + defined(__x86_64__) || defined(MIPSEL) || defined(_MIPSEL) || \ + defined(BIT_ZERO_ON_RIGHT) || defined(__alpha__) || defined(__alpha) || \ + (defined(__Lynx__) && defined(__x86__)) +#define BYTE_ORDER LITTLE_ENDIAN +#endif + +#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \ + defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \ + defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\ + defined(apollo) || defined(__convex__) || defined(_CRAY) || \ + defined(__hppa) || defined(__hp9000) || \ + defined(__hp9000s300) || defined(__hp9000s700) || \ + defined(__hp3000s900) || defined(__hpux) || defined(MPE) || \ + defined (BIT_ZERO_ON_LEFT) || defined(m68k) || defined(__sparc) || \ + (defined(__Lynx__) && \ + (defined(__68k__) || defined(__sparc__) || defined(__powerpc__))) +#define BYTE_ORDER BIG_ENDIAN +#endif +#endif /* __linux */ +#endif /* BSD */ +#endif /* BYTE_ORDER */ + +#if !defined(BYTE_ORDER) || \ + (BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN && \ + BYTE_ORDER != PDP_ENDIAN) + /* you must determine what the correct bit order is for + * your compiler - the next line is an intentional error + * which will force your compiles to bomb until you fix + * the above macros. + */ + error "Undefined or invalid BYTE_ORDER"; +#endif + +/*% + * Structure for query header. The order of the fields is machine- and + * compiler-dependent, depending on the byte/bit order and the layout + * of bit fields. We use bit fields only in int variables, as this + * is all ANSI requires. This requires a somewhat confusing rearrangement. + */ + +typedef struct { + unsigned id :16; /*%< query identification number */ +#if BYTE_ORDER == BIG_ENDIAN + /* fields in third byte */ + unsigned qr: 1; /*%< response flag */ + unsigned opcode: 4; /*%< purpose of message */ + unsigned aa: 1; /*%< authoritive answer */ + unsigned tc: 1; /*%< truncated message */ + unsigned rd: 1; /*%< recursion desired */ + /* fields in fourth byte */ + unsigned ra: 1; /*%< recursion available */ + unsigned unused :1; /*%< unused bits (MBZ as of 4.9.3a3) */ + unsigned ad: 1; /*%< authentic data from named */ + unsigned cd: 1; /*%< checking disabled by resolver */ + unsigned rcode :4; /*%< response code */ +#endif +#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN + /* fields in third byte */ + unsigned rd :1; /*%< recursion desired */ + unsigned tc :1; /*%< truncated message */ + unsigned aa :1; /*%< authoritive answer */ + unsigned opcode :4; /*%< purpose of message */ + unsigned qr :1; /*%< response flag */ + /* fields in fourth byte */ + unsigned rcode :4; /*%< response code */ + unsigned cd: 1; /*%< checking disabled by resolver */ + unsigned ad: 1; /*%< authentic data from named */ + unsigned unused :1; /*%< unused bits (MBZ as of 4.9.3a3) */ + unsigned ra :1; /*%< recursion available */ +#endif + /* remaining bytes */ + unsigned qdcount :16; /*%< number of question entries */ + unsigned ancount :16; /*%< number of answer entries */ + unsigned nscount :16; /*%< number of authority entries */ + unsigned arcount :16; /*%< number of resource entries */ +} HEADER; + +#define PACKETSZ NS_PACKETSZ +#define MAXDNAME NS_MAXDNAME +#define MAXCDNAME NS_MAXCDNAME +#define MAXLABEL NS_MAXLABEL +#define HFIXEDSZ NS_HFIXEDSZ +#define QFIXEDSZ NS_QFIXEDSZ +#define RRFIXEDSZ NS_RRFIXEDSZ +#define INT32SZ NS_INT32SZ +#define INT16SZ NS_INT16SZ +#define INT8SZ NS_INT8SZ +#define INADDRSZ NS_INADDRSZ +#define IN6ADDRSZ NS_IN6ADDRSZ +#define INDIR_MASK NS_CMPRSFLGS +#define NAMESERVER_PORT NS_DEFAULTPORT + +#define S_ZONE ns_s_zn +#define S_PREREQ ns_s_pr +#define S_UPDATE ns_s_ud +#define S_ADDT ns_s_ar + +#define QUERY ns_o_query +#define IQUERY ns_o_iquery +#define STATUS ns_o_status +#define NS_NOTIFY_OP ns_o_notify +#define NS_UPDATE_OP ns_o_update + +#define NOERROR ns_r_noerror +#define FORMERR ns_r_formerr +#define SERVFAIL ns_r_servfail +#define NXDOMAIN ns_r_nxdomain +#define NOTIMP ns_r_notimpl +#define REFUSED ns_r_refused +#define YXDOMAIN ns_r_yxdomain +#define YXRRSET ns_r_yxrrset +#define NXRRSET ns_r_nxrrset +#define NOTAUTH ns_r_notauth +#define NOTZONE ns_r_notzone +/*#define BADSIG ns_r_badsig*/ +/*#define BADKEY ns_r_badkey*/ +/*#define BADTIME ns_r_badtime*/ + + +#define DELETE ns_uop_delete +#define ADD ns_uop_add + +#define T_A ns_t_a +#define T_NS ns_t_ns +#define T_MD ns_t_md +#define T_MF ns_t_mf +#define T_CNAME ns_t_cname +#define T_SOA ns_t_soa +#define T_MB ns_t_mb +#define T_MG ns_t_mg +#define T_MR ns_t_mr +#define T_NULL ns_t_null +#define T_WKS ns_t_wks +#define T_PTR ns_t_ptr +#define T_HINFO ns_t_hinfo +#define T_MINFO ns_t_minfo +#define T_MX ns_t_mx +#define T_TXT ns_t_txt +#define T_RP ns_t_rp +#define T_AFSDB ns_t_afsdb +#define T_X25 ns_t_x25 +#define T_ISDN ns_t_isdn +#define T_RT ns_t_rt +#define T_NSAP ns_t_nsap +#define T_NSAP_PTR ns_t_nsap_ptr +#define T_SIG ns_t_sig +#define T_KEY ns_t_key +#define T_PX ns_t_px +#define T_GPOS ns_t_gpos +#define T_AAAA ns_t_aaaa +#define T_LOC ns_t_loc +#define T_NXT ns_t_nxt +#define T_EID ns_t_eid +#define T_NIMLOC ns_t_nimloc +#define T_SRV ns_t_srv +#define T_ATMA ns_t_atma +#define T_NAPTR ns_t_naptr +#define T_A6 ns_t_a6 +#define T_TSIG ns_t_tsig +#define T_IXFR ns_t_ixfr +#define T_AXFR ns_t_axfr +#define T_MAILB ns_t_mailb +#define T_MAILA ns_t_maila +#define T_ANY ns_t_any + +#define C_IN ns_c_in +#define C_CHAOS ns_c_chaos +#define C_HS ns_c_hs +/* BIND_UPDATE */ +#define C_NONE ns_c_none +#define C_ANY ns_c_any + +#define GETSHORT NS_GET16 +#define GETLONG NS_GET32 +#define PUTSHORT NS_PUT16 +#define PUTLONG NS_PUT32 + +#endif /* _ARPA_NAMESER_COMPAT_ */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/include/fd_setsize.h b/contrib/bind-9.5.2/lib/bind/include/fd_setsize.h new file mode 100644 index 0000000000..0e21049742 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/fd_setsize.h @@ -0,0 +1,10 @@ +#ifndef _FD_SETSIZE_H +#define _FD_SETSIZE_H + +/*% + * If you need a bigger FD_SETSIZE, this is NOT the place to set it. + * This file is a fallback for BIND ports which don't specify their own. + */ + +#endif /* _FD_SETSIZE_H */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/include/hesiod.h b/contrib/bind-9.5.2/lib/bind/include/hesiod.h new file mode 100644 index 0000000000..d64c0c5e80 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/hesiod.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +/*! \file + * \brief + * This file is primarily maintained by and . + */ + +/* + * $Id: hesiod.h,v 1.4 2005/04/27 04:56:14 sra Exp $ + */ + +#ifndef _HESIOD_H_INCLUDED +#define _HESIOD_H_INCLUDED + +int hesiod_init __P((void **)); +void hesiod_end __P((void *)); +char * hesiod_to_bind __P((void *, const char *, const char *)); +char ** hesiod_resolve __P((void *, const char *, const char *)); +void hesiod_free_list __P((void *, char **)); +struct __res_state * __hesiod_res_get __P((void *)); +void __hesiod_res_set __P((void *, struct __res_state *, + void (*)(void *))); + +#endif /*_HESIOD_H_INCLUDED*/ diff --git a/contrib/bind-9.5.2/lib/bind/include/irp.h b/contrib/bind-9.5.2/lib/bind/include/irp.h new file mode 100644 index 0000000000..1290bd068f --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/irp.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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: irp.h,v 1.4 2005/04/27 04:56:15 sra Exp $ + */ + +#ifndef _IRP_H_INCLUDED +#define _IRP_H_INCLUDED + +/*! \file */ + +#define IRPD_TIMEOUT 30 /*%< seconds */ +#define IRPD_MAXSESS 50 /*%< number of simultaneous sessions. */ +#define IRPD_PORT 6660 /*%< 10 times the number of the beast. */ +#define IRPD_PATH "/var/run/irpd" /*%< af_unix socket path */ + +/* If sets the environment variable IRPDSERVER to an IP address + (e.g. "192.5.5.1"), then that's the host the client expects irpd to be + running on. */ +#define IRPD_HOST_ENV "IRPDSERVER" + +/* Protocol response codes. */ +#define IRPD_WELCOME_CODE 200 +#define IRPD_NOT_WELCOME_CODE 500 + +#define IRPD_GETHOST_ERROR 510 +#define IRPD_GETHOST_NONE 210 +#define IRPD_GETHOST_OK 211 +#define IRPD_GETHOST_SETOK 212 + +#define IRPD_GETNET_ERROR 520 +#define IRPD_GETNET_NONE 220 +#define IRPD_GETNET_OK 221 +#define IRPD_GETNET_SETOK 222 + +#define IRPD_GETUSER_ERROR 530 +#define IRPD_GETUSER_NONE 230 +#define IRPD_GETUSER_OK 231 +#define IRPD_GETUSER_SETOK 232 + +#define IRPD_GETGROUP_ERROR 540 +#define IRPD_GETGROUP_NONE 240 +#define IRPD_GETGROUP_OK 241 +#define IRPD_GETGROUP_SETOK 242 + +#define IRPD_GETSERVICE_ERROR 550 +#define IRPD_GETSERVICE_NONE 250 +#define IRPD_GETSERVICE_OK 251 +#define IRPD_GETSERVICE_SETOK 252 + +#define IRPD_GETPROTO_ERROR 560 +#define IRPD_GETPROTO_NONE 260 +#define IRPD_GETPROTO_OK 261 +#define IRPD_GETPROTO_SETOK 262 + +#define IRPD_GETNETGR_ERROR 570 +#define IRPD_GETNETGR_NONE 270 +#define IRPD_GETNETGR_OK 271 +#define IRPD_GETNETGR_NOMORE 272 +#define IRPD_GETNETGR_MATCHES 273 +#define IRPD_GETNETGR_NOMATCH 274 +#define IRPD_GETNETGR_SETOK 275 +#define IRPD_GETNETGR_SETERR 276 + +#define irs_irp_read_body __irs_irp_read_body +#define irs_irp_read_response __irs_irp_read_response +#define irs_irp_disconnect __irs_irp_disconnect +#define irs_irp_connect __irs_irp_connect +#define irs_irp_connection_setup __irs_irp_connection_setup +#define irs_irp_send_command __irs_irp_send_command + +struct irp_p; + +char *irs_irp_read_body(struct irp_p *, size_t *); +int irs_irp_read_response(struct irp_p *, char *, size_t); +void irs_irp_disconnect(struct irp_p *); +int irs_irp_connect(struct irp_p *); +int irs_irp_is_connected(struct irp_p *); +int irs_irp_connection_setup(struct irp_p *, int *); +#ifdef __GNUC__ +int irs_irp_send_command(struct irp_p *, const char *, ...) + __attribute__((__format__(__printf__, 2, 3))); +#else +int irs_irp_send_command(struct irp_p *, const char *, ...); +#endif +int irs_irp_get_full_response(struct irp_p *, int *, char *, size_t, + char **, size_t *); +int irs_irp_read_line(struct irp_p *, char *, int); + +#endif + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/include/irs.h b/contrib/bind-9.5.2/lib/bind/include/irs.h new file mode 100644 index 0000000000..42d4890dfd --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/irs.h @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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: irs.h,v 1.5 2005/04/27 04:56:15 sra Exp $ + */ + +#ifndef _IRS_H_INCLUDED +#define _IRS_H_INCLUDED + +/*! \file */ + +#include + +#include + +#include +#include +#include +#include + +/*% + * This is the group map class. + */ +struct irs_gr { + void * private; + void (*close) __P((struct irs_gr *)); + struct group * (*next) __P((struct irs_gr *)); + struct group * (*byname) __P((struct irs_gr *, const char *)); + struct group * (*bygid) __P((struct irs_gr *, gid_t)); + int (*list) __P((struct irs_gr *, const char *, + gid_t, gid_t *, int *)); + void (*rewind) __P((struct irs_gr *)); + void (*minimize) __P((struct irs_gr *)); + struct __res_state * (*res_get) __P((struct irs_gr *)); + void (*res_set) __P((struct irs_gr *, res_state, + void (*)(void *))); +}; + +/*% + * This is the password map class. + */ +struct irs_pw { + void * private; + void (*close) __P((struct irs_pw *)); + struct passwd * (*next) __P((struct irs_pw *)); + struct passwd * (*byname) __P((struct irs_pw *, const char *)); + struct passwd * (*byuid) __P((struct irs_pw *, uid_t)); + void (*rewind) __P((struct irs_pw *)); + void (*minimize) __P((struct irs_pw *)); + struct __res_state * (*res_get) __P((struct irs_pw *)); + void (*res_set) __P((struct irs_pw *, res_state, + void (*)(void *))); +}; + +/*% + * This is the service map class. + */ +struct irs_sv { + void * private; + void (*close) __P((struct irs_sv *)); + struct servent *(*byname) __P((struct irs_sv *, + const char *, const char *)); + struct servent *(*byport) __P((struct irs_sv *, int, const char *)); + struct servent *(*next) __P((struct irs_sv *)); + void (*rewind) __P((struct irs_sv *)); + void (*minimize) __P((struct irs_sv *)); + struct __res_state * (*res_get) __P((struct irs_sv *)); + void (*res_set) __P((struct irs_sv *, res_state, + void (*)(void *))); +}; + +/*% + * This is the protocols map class. + */ +struct irs_pr { + void * private; + void (*close) __P((struct irs_pr *)); + struct protoent *(*byname) __P((struct irs_pr *, const char *)); + struct protoent *(*bynumber) __P((struct irs_pr *, int)); + struct protoent *(*next) __P((struct irs_pr *)); + void (*rewind) __P((struct irs_pr *)); + void (*minimize) __P((struct irs_pr *)); + struct __res_state * (*res_get) __P((struct irs_pr *)); + void (*res_set) __P((struct irs_pr *, res_state, + void (*)(void *))); +}; + +/*% + * This is the hosts map class. + */ +struct irs_ho { + void * private; + void (*close) __P((struct irs_ho *)); + struct hostent *(*byname) __P((struct irs_ho *, const char *)); + struct hostent *(*byname2) __P((struct irs_ho *, const char *, int)); + struct hostent *(*byaddr) __P((struct irs_ho *, + const void *, int, int)); + struct hostent *(*next) __P((struct irs_ho *)); + void (*rewind) __P((struct irs_ho *)); + void (*minimize) __P((struct irs_ho *)); + struct __res_state * (*res_get) __P((struct irs_ho *)); + void (*res_set) __P((struct irs_ho *, res_state, + void (*)(void *))); + struct addrinfo *(*addrinfo) __P((struct irs_ho *, const char *, + const struct addrinfo *)); +}; + +/*% + * This is the networks map class. + */ +struct irs_nw { + void * private; + void (*close) __P((struct irs_nw *)); + struct nwent * (*byname) __P((struct irs_nw *, const char *, int)); + struct nwent * (*byaddr) __P((struct irs_nw *, void *, int, int)); + struct nwent * (*next) __P((struct irs_nw *)); + void (*rewind) __P((struct irs_nw *)); + void (*minimize) __P((struct irs_nw *)); + struct __res_state * (*res_get) __P((struct irs_nw *)); + void (*res_set) __P((struct irs_nw *, res_state, + void (*)(void *))); +}; + +/*% + * This is the netgroups map class. + */ +struct irs_ng { + void * private; + void (*close) __P((struct irs_ng *)); + int (*next) __P((struct irs_ng *, const char **, + const char **, const char **)); + int (*test) __P((struct irs_ng *, const char *, + const char *, const char *, + const char *)); + void (*rewind) __P((struct irs_ng *, const char *)); + void (*minimize) __P((struct irs_ng *)); +}; + +/*% + * This is the generic map class, which copies the front of all others. + */ +struct irs_map { + void * private; + void (*close) __P((void *)); +}; + +/*% + * This is the accessor class. It contains pointers to all of the + * initializers for the map classes for a particular accessor. + */ +struct irs_acc { + void * private; + void (*close) __P((struct irs_acc *)); + struct irs_gr * (*gr_map) __P((struct irs_acc *)); + struct irs_pw * (*pw_map) __P((struct irs_acc *)); + struct irs_sv * (*sv_map) __P((struct irs_acc *)); + struct irs_pr * (*pr_map) __P((struct irs_acc *)); + struct irs_ho * (*ho_map) __P((struct irs_acc *)); + struct irs_nw * (*nw_map) __P((struct irs_acc *)); + struct irs_ng * (*ng_map) __P((struct irs_acc *)); + struct __res_state * (*res_get) __P((struct irs_acc *)); + void (*res_set) __P((struct irs_acc *, res_state, + void (*)(void *))); +}; + +/*% + * This is because the official definition of "struct netent" has no + * concept of CIDR even though it allows variant address families (on + * output but not input). The compatibility stubs convert the structs + * below into "struct netent"'s. + */ +struct nwent { + char *n_name; /*%< official name of net */ + char **n_aliases; /*%< alias list */ + int n_addrtype; /*%< net address type */ + void *n_addr; /*%< network address */ + int n_length; /*%< address length, in bits */ +}; + +/*% + * Hide external function names from POSIX. + */ +#define irs_gen_acc __irs_gen_acc +#define irs_lcl_acc __irs_lcl_acc +#define irs_dns_acc __irs_dns_acc +#define irs_nis_acc __irs_nis_acc +#define irs_irp_acc __irs_irp_acc +#define irs_destroy __irs_destroy +#define irs_dns_gr __irs_dns_gr +#define irs_dns_ho __irs_dns_ho +#define irs_dns_nw __irs_dns_nw +#define irs_dns_pr __irs_dns_pr +#define irs_dns_pw __irs_dns_pw +#define irs_dns_sv __irs_dns_sv +#define irs_gen_gr __irs_gen_gr +#define irs_gen_ho __irs_gen_ho +#define irs_gen_ng __irs_gen_ng +#define irs_gen_nw __irs_gen_nw +#define irs_gen_pr __irs_gen_pr +#define irs_gen_pw __irs_gen_pw +#define irs_gen_sv __irs_gen_sv +#define irs_irp_get_full_response __irs_irp_get_full_response +#define irs_irp_gr __irs_irp_gr +#define irs_irp_ho __irs_irp_ho +#define irs_irp_is_connected __irs_irp_is_connected +#define irs_irp_ng __irs_irp_ng +#define irs_irp_nw __irs_irp_nw +#define irs_irp_pr __irs_irp_pr +#define irs_irp_pw __irs_irp_pw +#define irs_irp_read_line __irs_irp_read_line +#define irs_irp_sv __irs_irp_sv +#define irs_lcl_gr __irs_lcl_gr +#define irs_lcl_ho __irs_lcl_ho +#define irs_lcl_ng __irs_lcl_ng +#define irs_lcl_nw __irs_lcl_nw +#define irs_lcl_pr __irs_lcl_pr +#define irs_lcl_pw __irs_lcl_pw +#define irs_lcl_sv __irs_lcl_sv +#define irs_nis_gr __irs_nis_gr +#define irs_nis_ho __irs_nis_ho +#define irs_nis_ng __irs_nis_ng +#define irs_nis_nw __irs_nis_nw +#define irs_nis_pr __irs_nis_pr +#define irs_nis_pw __irs_nis_pw +#define irs_nis_sv __irs_nis_sv +#define net_data_create __net_data_create +#define net_data_destroy __net_data_destroy +#define net_data_minimize __net_data_minimize + +/*% + * Externs. + */ +extern struct irs_acc * irs_gen_acc __P((const char *, const char *)); +extern struct irs_acc * irs_lcl_acc __P((const char *)); +extern struct irs_acc * irs_dns_acc __P((const char *)); +extern struct irs_acc * irs_nis_acc __P((const char *)); +extern struct irs_acc * irs_irp_acc __P((const char *)); + +extern void irs_destroy __P((void)); + +/*% + * These forward declarations are for the semi-private functions in + * the get*.c files. Each of these funcs implements the real get* + * functionality and the standard versions are just wrappers that + * call these. Apart from the wrappers, only irpd is expected to + * call these directly, hence these decls are put here and not in + * the /usr/include replacements. + */ + +struct net_data; /*%< forward */ +/* + * net_data_create gets a singleton net_data object. net_data_init + * creates as many net_data objects as times it is called. Clients using + * the default interface will use net_data_create by default. Servers will + * probably want net_data_init (one call per client) + */ +struct net_data *net_data_create __P((const char *)); +struct net_data *net_data_init __P((const char *)); +void net_data_destroy __P((void *)); + +extern struct group *getgrent_p __P((struct net_data *)); +extern struct group *getgrnam_p __P((const char *, struct net_data *)); +extern struct group *getgrgid_p __P((gid_t, struct net_data *)); +extern int setgroupent_p __P((int, struct net_data *)); +extern void endgrent_p __P((struct net_data *)); +extern int getgrouplist_p __P((const char *, gid_t, gid_t *, int *, + struct net_data *)); + +#ifdef SETGRENT_VOID +extern void setgrent_p __P((struct net_data *)); +#else +extern int setgrent_p __P((struct net_data *)); +#endif + +extern struct hostent *gethostbyname_p __P((const char *, + struct net_data *)); +extern struct hostent *gethostbyname2_p __P((const char *, int, + struct net_data *)); +extern struct hostent *gethostbyaddr_p __P((const char *, int, int, + struct net_data *)); +extern struct hostent *gethostent_p __P((struct net_data *)); +extern void sethostent_p __P((int, struct net_data *)); +extern void endhostent_p __P((struct net_data *)); +extern struct hostent *getipnodebyname_p __P((const char *, int, int, int *, + struct net_data *)); +extern struct hostent *getipnodebyaddr_p __P((const void *, size_t, + int, int *, struct net_data *)); + +extern struct netent *getnetent_p __P((struct net_data *)); +extern struct netent *getnetbyname_p __P((const char *, struct net_data *)); +extern struct netent *getnetbyaddr_p __P((unsigned long, int, + struct net_data *)); +extern void setnetent_p __P((int, struct net_data *)); +extern void endnetent_p __P((struct net_data *)); + +extern void setnetgrent_p __P((const char *, struct net_data *)); +extern void endnetgrent_p __P((struct net_data *)); +extern int innetgr_p __P((const char *, const char *, const char *, + const char *, struct net_data *)); +extern int getnetgrent_p __P((const char **, const char **, + const char **, struct net_data *)); + +extern struct protoent *getprotoent_p __P((struct net_data *)); +extern struct protoent *getprotobyname_p __P((const char *, + struct net_data *)); +extern struct protoent *getprotobynumber_p __P((int, struct net_data *)); +extern void setprotoent_p __P((int, struct net_data *)); +extern void endprotoent_p __P((struct net_data *)); + + +extern struct passwd *getpwent_p __P((struct net_data *)); +extern struct passwd *getpwnam_p __P((const char *, struct net_data *)); +extern struct passwd *getpwuid_p __P((uid_t, struct net_data *)); +extern int setpassent_p __P((int, struct net_data *)); +extern void endpwent_p __P((struct net_data *)); + +#ifdef SETPWENT_VOID +extern void setpwent_p __P((struct net_data *)); +#else +extern int setpwent_p __P((struct net_data *)); +#endif + +extern struct servent *getservent_p __P((struct net_data *)); +extern struct servent *getservbyname_p __P((const char *, const char *, + struct net_data *)); +extern struct servent *getservbyport_p __P((int, const char *, + struct net_data *)); +extern void setservent_p __P((int, struct net_data *)); +extern void endservent_p __P((struct net_data *)); + +#endif /*_IRS_H_INCLUDED*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/include/isc/assertions.h b/contrib/bind-9.5.2/lib/bind/include/isc/assertions.h new file mode 100644 index 0000000000..3593a687e6 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/isc/assertions.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1997-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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: assertions.h,v 1.3.672.1 2008/10/15 03:56:26 marka Exp $ + */ + +#ifndef ASSERTIONS_H +#define ASSERTIONS_H 1 + +typedef enum { + assert_require, assert_ensure, assert_insist, assert_invariant +} assertion_type; + +typedef void (*assertion_failure_callback)(const char *, int, assertion_type, + const char *, int); + +/* coverity[+kill] */ +extern assertion_failure_callback __assertion_failed; +void set_assertion_failure_callback(assertion_failure_callback f); +const char *assertion_type_to_text(assertion_type type); + +#if defined(CHECK_ALL) || defined(__COVERITY__) +#define CHECK_REQUIRE 1 +#define CHECK_ENSURE 1 +#define CHECK_INSIST 1 +#define CHECK_INVARIANT 1 +#endif + +#if defined(CHECK_NONE) && !defined(__COVERITY__) +#define CHECK_REQUIRE 0 +#define CHECK_ENSURE 0 +#define CHECK_INSIST 0 +#define CHECK_INVARIANT 0 +#endif + +#ifndef CHECK_REQUIRE +#define CHECK_REQUIRE 1 +#endif + +#ifndef CHECK_ENSURE +#define CHECK_ENSURE 1 +#endif + +#ifndef CHECK_INSIST +#define CHECK_INSIST 1 +#endif + +#ifndef CHECK_INVARIANT +#define CHECK_INVARIANT 1 +#endif + +#if CHECK_REQUIRE != 0 +#define REQUIRE(cond) \ + ((void) ((cond) || \ + ((__assertion_failed)(__FILE__, __LINE__, assert_require, \ + #cond, 0), 0))) +#define REQUIRE_ERR(cond) \ + ((void) ((cond) || \ + ((__assertion_failed)(__FILE__, __LINE__, assert_require, \ + #cond, 1), 0))) +#else +#define REQUIRE(cond) ((void) (cond)) +#define REQUIRE_ERR(cond) ((void) (cond)) +#endif /* CHECK_REQUIRE */ + +#if CHECK_ENSURE != 0 +#define ENSURE(cond) \ + ((void) ((cond) || \ + ((__assertion_failed)(__FILE__, __LINE__, assert_ensure, \ + #cond, 0), 0))) +#define ENSURE_ERR(cond) \ + ((void) ((cond) || \ + ((__assertion_failed)(__FILE__, __LINE__, assert_ensure, \ + #cond, 1), 0))) +#else +#define ENSURE(cond) ((void) (cond)) +#define ENSURE_ERR(cond) ((void) (cond)) +#endif /* CHECK_ENSURE */ + +#if CHECK_INSIST != 0 +#define INSIST(cond) \ + ((void) ((cond) || \ + ((__assertion_failed)(__FILE__, __LINE__, assert_insist, \ + #cond, 0), 0))) +#define INSIST_ERR(cond) \ + ((void) ((cond) || \ + ((__assertion_failed)(__FILE__, __LINE__, assert_insist, \ + #cond, 1), 0))) +#else +#define INSIST(cond) ((void) (cond)) +#define INSIST_ERR(cond) ((void) (cond)) +#endif /* CHECK_INSIST */ + +#if CHECK_INVARIANT != 0 +#define INVARIANT(cond) \ + ((void) ((cond) || \ + ((__assertion_failed)(__FILE__, __LINE__, assert_invariant, \ + #cond, 0), 0))) +#define INVARIANT_ERR(cond) \ + ((void) ((cond) || \ + ((__assertion_failed)(__FILE__, __LINE__, assert_invariant, \ + #cond, 1), 0))) +#else +#define INVARIANT(cond) ((void) (cond)) +#define INVARIANT_ERR(cond) ((void) (cond)) +#endif /* CHECK_INVARIANT */ +#endif /* ASSERTIONS_H */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/include/isc/ctl.h b/contrib/bind-9.5.2/lib/bind/include/isc/ctl.h new file mode 100644 index 0000000000..e2ba20201d --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/isc/ctl.h @@ -0,0 +1,112 @@ +#ifndef ISC_CTL_H +#define ISC_CTL_H + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1998,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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: ctl.h,v 1.5 2005/04/27 04:56:17 sra Exp $ + */ + +/*! \file */ + +#include +#include + +#include + +/* Macros. */ + +#define CTL_MORE 0x0001 /*%< More will be / should be sent. */ +#define CTL_EXIT 0x0002 /*%< Close connection after this. */ +#define CTL_DATA 0x0004 /*%< Go into / this is DATA mode. */ +/* Types. */ + +struct ctl_cctx; +struct ctl_sctx; +struct ctl_sess; +struct ctl_verb; + +enum ctl_severity { ctl_debug, ctl_warning, ctl_error }; + +typedef void (*ctl_logfunc)(enum ctl_severity, const char *, ...); + +typedef void (*ctl_verbfunc)(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, const char *, + u_int, const void *, void *); + +typedef void (*ctl_srvrdone)(struct ctl_sctx *, struct ctl_sess *, void *); + +typedef void (*ctl_clntdone)(struct ctl_cctx *, void *, const char *, u_int); + +struct ctl_verb { + const char * name; + ctl_verbfunc func; + const char * help; +}; + +/* General symbols. */ + +#define ctl_logger __ctl_logger + +#ifdef __GNUC__ +void ctl_logger(enum ctl_severity, const char *, ...) + __attribute__((__format__(__printf__, 2, 3))); +#else +void ctl_logger(enum ctl_severity, const char *, ...); +#endif + +/* Client symbols. */ + +#define ctl_client __ctl_client +#define ctl_endclient __ctl_endclient +#define ctl_command __ctl_command + +struct ctl_cctx * ctl_client(evContext, const struct sockaddr *, size_t, + const struct sockaddr *, size_t, + ctl_clntdone, void *, + u_int, ctl_logfunc); +void ctl_endclient(struct ctl_cctx *); +int ctl_command(struct ctl_cctx *, const char *, size_t, + ctl_clntdone, void *); + +/* Server symbols. */ + +#define ctl_server __ctl_server +#define ctl_endserver __ctl_endserver +#define ctl_response __ctl_response +#define ctl_sendhelp __ctl_sendhelp +#define ctl_getcsctx __ctl_getcsctx +#define ctl_setcsctx __ctl_setcsctx + +struct ctl_sctx * ctl_server(evContext, const struct sockaddr *, size_t, + const struct ctl_verb *, + u_int, u_int, + u_int, int, int, + ctl_logfunc, void *); +void ctl_endserver(struct ctl_sctx *); +void ctl_response(struct ctl_sess *, u_int, + const char *, u_int, const void *, + ctl_srvrdone, void *, + const char *, size_t); +void ctl_sendhelp(struct ctl_sess *, u_int); +void * ctl_getcsctx(struct ctl_sess *); +void * ctl_setcsctx(struct ctl_sess *, void *); + +#endif /*ISC_CTL_H*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/include/isc/dst.h b/contrib/bind-9.5.2/lib/bind/include/isc/dst.h new file mode 100644 index 0000000000..90a9e67468 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/isc/dst.h @@ -0,0 +1,168 @@ +#ifndef DST_H +#define DST_H + +#ifndef HAS_DST_KEY +typedef struct dst_key { + char *dk_key_name; /*%< name of the key */ + int dk_key_size; /*%< this is the size of the key in bits */ + int dk_proto; /*%< what protocols this key can be used for */ + int dk_alg; /*%< algorithm number from key record */ + u_int32_t dk_flags; /*%< and the flags of the public key */ + u_int16_t dk_id; /*%< identifier of the key */ +} DST_KEY; +#endif /* HAS_DST_KEY */ +/* + * do not taint namespace + */ +#define dst_bsafe_init __dst_bsafe_init +#define dst_buffer_to_key __dst_buffer_to_key +#define dst_check_algorithm __dst_check_algorithm +#define dst_compare_keys __dst_compare_keys +#define dst_cylink_init __dst_cylink_init +#define dst_dnskey_to_key __dst_dnskey_to_key +#define dst_eay_dss_init __dst_eay_dss_init +#define dst_free_key __dst_free_key +#define dst_generate_key __dst_generate_key +#define dst_hmac_md5_init __dst_hmac_md5_init +#define dst_init __dst_init +#define dst_key_to_buffer __dst_key_to_buffer +#define dst_key_to_dnskey __dst_key_to_dnskey +#define dst_read_key __dst_read_key +#define dst_rsaref_init __dst_rsaref_init +#define dst_s_build_filename __dst_s_build_filename +#define dst_s_calculate_bits __dst_s_calculate_bits +#define dst_s_conv_bignum_b64_to_u8 __dst_s_conv_bignum_b64_to_u8 +#define dst_s_conv_bignum_u8_to_b64 __dst_s_conv_bignum_u8_to_b64 +#define dst_s_dns_key_id __dst_s_dns_key_id +#define dst_s_dump __dst_s_dump +#define dst_s_filename_length __dst_s_filename_length +#define dst_s_fopen __dst_s_fopen +#define dst_s_get_int16 __dst_s_get_int16 +#define dst_s_get_int32 __dst_s_get_int32 +#define dst_s_id_calc __dst_s_id_calc +#define dst_s_put_int16 __dst_s_put_int16 +#define dst_s_put_int32 __dst_s_put_int32 +#define dst_s_quick_random __dst_s_quick_random +#define dst_s_quick_random_set __dst_s_quick_random_set +#define dst_s_random __dst_s_random +#define dst_s_semi_random __dst_s_semi_random +#define dst_s_verify_str __dst_s_verify_str +#define dst_sig_size __dst_sig_size +#define dst_sign_data __dst_sign_data +#define dst_verify_data __dst_verify_data +#define dst_write_key __dst_write_key + +/* + * DST Crypto API defintions + */ +void dst_init(void); +int dst_check_algorithm(const int); + + +int dst_sign_data(const int, /*!< specifies INIT/UPDATE/FINAL/ALL */ + DST_KEY *, /*!< the key to use */ + void **, /*!< pointer to state structure */ + const u_char *, /*!< data to be signed */ + const int, /*!< length of input data */ + u_char *, /*!< buffer to write signature to */ + const int); /*!< size of output buffer */ +int dst_verify_data(const int, /*!< specifies INIT/UPDATE/FINAL/ALL */ + DST_KEY *, /*!< the key to use */ + void **, /*!< pointer to state structure */ + const u_char *, /*!< data to be verified */ + const int, /*!< length of input data */ + const u_char *, /*!< buffer containing signature */ + const int); /*!< length of signature */ +DST_KEY *dst_read_key(const char *, /*!< name of key */ + const u_int16_t, /*!< key tag identifier */ + const int, /*!< key algorithm */ + const int); /*!< Private/PublicKey wanted */ +int dst_write_key(const DST_KEY *, /*!< key to write out */ + const int); /*!< Public/Private */ +DST_KEY *dst_dnskey_to_key(const char *, /*!< KEY record name */ + const u_char *, /*!< KEY RDATA */ + const int); /*!< size of input buffer */ +int dst_key_to_dnskey(const DST_KEY *, /*!< key to translate */ + u_char *, /*!< output buffer */ + const int); /*!< size of out_storage */ +DST_KEY *dst_buffer_to_key(const char *, /*!< name of the key */ + const int, /*!< algorithm */ + const int, /*!< dns flags */ + const int, /*!< dns protocol */ + const u_char *, /*!< key in dns wire fmt */ + const int); /*!< size of key */ +int dst_key_to_buffer(DST_KEY *, u_char *, int); + +DST_KEY *dst_generate_key(const char *, /*!< name of new key */ + const int, /*!< key algorithm to generate */ + const int, /*!< size of new key */ + const int, /*!< alg dependent parameter */ + const int, /*!< key DNS flags */ + const int); /*!< key DNS protocol */ +DST_KEY *dst_free_key(DST_KEY *); +int dst_compare_keys(const DST_KEY *, const DST_KEY *); + +int dst_sig_size(DST_KEY *); + + +/* support for dns key tags/ids */ +u_int16_t dst_s_dns_key_id(const u_char *, const int); +u_int16_t dst_s_id_calc(const u_char *, const int); + +/* Used by callers as well as by the library. */ +#define RAW_KEY_SIZE 8192 /*%< large enough to store any key */ +/* DST_API control flags */ +/* These are used used in functions dst_sign_data and dst_verify_data */ +#define SIG_MODE_INIT 1 /*%< initialize digest */ +#define SIG_MODE_UPDATE 2 /*%< add data to digest */ +#define SIG_MODE_FINAL 4 /*%< generate/verify signature */ +#define SIG_MODE_ALL (SIG_MODE_INIT|SIG_MODE_UPDATE|SIG_MODE_FINAL) + +/* Flags for dst_read_private_key() */ +#define DST_FORCE_READ 0x1000000 +#define DST_CAN_SIGN 0x010F +#define DST_NO_AUTHEN 0x8000 +#define DST_EXTEND_FLAG 0x1000 +#define DST_STANDARD 0 +#define DST_PRIVATE 0x2000000 +#define DST_PUBLIC 0x4000000 +#define DST_RAND_SEMI 1 +#define DST_RAND_STD 2 +#define DST_RAND_KEY 3 +#define DST_RAND_DSS 4 + + +/* DST algorithm codes */ +#define KEY_RSA 1 +#define KEY_DH 2 +#define KEY_DSA 3 +#define KEY_PRIVATE 254 +#define KEY_EXPAND 255 +#define KEY_HMAC_MD5 157 +#define KEY_HMAC_SHA1 158 +#define UNKNOWN_KEYALG 0 +#define DST_MAX_ALGS KEY_HMAC_SHA1 + +/* DST constants to locations in KEY record changes in new KEY record */ +#define DST_FLAGS_SIZE 2 +#define DST_KEY_PROT 2 +#define DST_KEY_ALG 3 +#define DST_EXT_FLAG 4 +#define DST_KEY_START 4 + +#ifndef SIGN_F_NOKEY +#define SIGN_F_NOKEY 0xC000 +#endif + +/* error codes from dst routines */ +#define SIGN_INIT_FAILURE (-23) +#define SIGN_UPDATE_FAILURE (-24) +#define SIGN_FINAL_FAILURE (-25) +#define VERIFY_INIT_FAILURE (-26) +#define VERIFY_UPDATE_FAILURE (-27) +#define VERIFY_FINAL_FAILURE (-28) +#define MISSING_KEY_OR_SIGNATURE (-30) +#define UNSUPPORTED_KEYALG (-31) + +#endif /* DST_H */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/include/isc/eventlib.h b/contrib/bind-9.5.2/lib/bind/include/isc/eventlib.h new file mode 100644 index 0000000000..1a1ac89424 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/isc/eventlib.h @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1995-1999 by Internet Software Consortium + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +/* eventlib.h - exported interfaces for eventlib + * vix 09sep95 [initial] + * + * $Id: eventlib.h,v 1.5.574.1 2008/01/23 02:08:11 marka Exp $ + */ + +#ifndef _EVENTLIB_H +#define _EVENTLIB_H + +#include +#include +#include +#include + +#include + +#ifndef __P +# define __EVENTLIB_P_DEFINED +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif + +/* In the absence of branded types... */ +typedef struct { void *opaque; } evConnID; +typedef struct { void *opaque; } evFileID; +typedef struct { void *opaque; } evStreamID; +typedef struct { void *opaque; } evTimerID; +typedef struct { void *opaque; } evWaitID; +typedef struct { void *opaque; } evContext; +typedef struct { void *opaque; } evEvent; + +#define evInitID(id) ((id)->opaque = NULL) +#define evTestID(id) ((id).opaque != NULL) + +typedef void (*evConnFunc)__P((evContext, void *, int, const void *, int, + const void *, int)); +typedef void (*evFileFunc)__P((evContext, void *, int, int)); +typedef void (*evStreamFunc)__P((evContext, void *, int, int)); +typedef void (*evTimerFunc)__P((evContext, void *, + struct timespec, struct timespec)); +typedef void (*evWaitFunc)__P((evContext, void *, const void *)); + +typedef struct { unsigned char mask[256/8]; } evByteMask; +#define EV_BYTEMASK_BYTE(b) ((b) / 8) +#define EV_BYTEMASK_MASK(b) (1 << ((b) % 8)) +#define EV_BYTEMASK_SET(bm, b) \ + ((bm).mask[EV_BYTEMASK_BYTE(b)] |= EV_BYTEMASK_MASK(b)) +#define EV_BYTEMASK_CLR(bm, b) \ + ((bm).mask[EV_BYTEMASK_BYTE(b)] &= ~EV_BYTEMASK_MASK(b)) +#define EV_BYTEMASK_TST(bm, b) \ + ((bm).mask[EV_BYTEMASK_BYTE(b)] & EV_BYTEMASK_MASK(b)) + +#define EV_POLL 1 +#define EV_WAIT 2 +#define EV_NULL 4 + +#define EV_READ 1 +#define EV_WRITE 2 +#define EV_EXCEPT 4 + +#define EV_WASNONBLOCKING 8 /* Internal library use. */ + +/* eventlib.c */ +#define evCreate __evCreate +#define evSetDebug __evSetDebug +#define evDestroy __evDestroy +#define evGetNext __evGetNext +#define evDispatch __evDispatch +#define evDrop __evDrop +#define evMainLoop __evMainLoop +#define evHighestFD __evHighestFD +#define evGetOption __evGetOption +#define evSetOption __evSetOption + +int evCreate __P((evContext *)); +void evSetDebug __P((evContext, int, FILE *)); +int evDestroy __P((evContext)); +int evGetNext __P((evContext, evEvent *, int)); +int evDispatch __P((evContext, evEvent)); +void evDrop __P((evContext, evEvent)); +int evMainLoop __P((evContext)); +int evHighestFD __P((evContext)); +int evGetOption __P((evContext *, const char *, int *)); +int evSetOption __P((evContext *, const char *, int)); + +/* ev_connects.c */ +#define evListen __evListen +#define evConnect __evConnect +#define evCancelConn __evCancelConn +#define evHold __evHold +#define evUnhold __evUnhold +#define evTryAccept __evTryAccept + +int evListen __P((evContext, int, int, evConnFunc, void *, evConnID *)); +int evConnect __P((evContext, int, const void *, int, + evConnFunc, void *, evConnID *)); +int evCancelConn __P((evContext, evConnID)); +int evHold __P((evContext, evConnID)); +int evUnhold __P((evContext, evConnID)); +int evTryAccept __P((evContext, evConnID, int *)); + +/* ev_files.c */ +#define evSelectFD __evSelectFD +#define evDeselectFD __evDeselectFD + +int evSelectFD __P((evContext, int, int, evFileFunc, void *, evFileID *)); +int evDeselectFD __P((evContext, evFileID)); + +/* ev_streams.c */ +#define evConsIovec __evConsIovec +#define evWrite __evWrite +#define evRead __evRead +#define evTimeRW __evTimeRW +#define evUntimeRW __evUntimeRW +#define evCancelRW __evCancelRW + +struct iovec evConsIovec __P((void *, size_t)); +int evWrite __P((evContext, int, const struct iovec *, int, + evStreamFunc func, void *, evStreamID *)); +int evRead __P((evContext, int, const struct iovec *, int, + evStreamFunc func, void *, evStreamID *)); +int evTimeRW __P((evContext, evStreamID, evTimerID timer)); +int evUntimeRW __P((evContext, evStreamID)); +int evCancelRW __P((evContext, evStreamID)); + +/* ev_timers.c */ +#define evConsTime __evConsTime +#define evAddTime __evAddTime +#define evSubTime __evSubTime +#define evCmpTime __evCmpTime +#define evTimeSpec __evTimeSpec +#define evTimeVal __evTimeVal + +#define evNowTime __evNowTime +#define evUTCTime __evUTCTime +#define evLastEventTime __evLastEventTime +#define evSetTimer __evSetTimer +#define evClearTimer __evClearTimer +#define evConfigTimer __evConfigTimer +#define evResetTimer __evResetTimer +#define evSetIdleTimer __evSetIdleTimer +#define evClearIdleTimer __evClearIdleTimer +#define evResetIdleTimer __evResetIdleTimer +#define evTouchIdleTimer __evTouchIdleTimer + +struct timespec evConsTime __P((time_t sec, long nsec)); +struct timespec evAddTime __P((struct timespec, struct timespec)); +struct timespec evSubTime __P((struct timespec, struct timespec)); +struct timespec evNowTime __P((void)); +struct timespec evUTCTime __P((void)); +struct timespec evLastEventTime __P((evContext)); +struct timespec evTimeSpec __P((struct timeval)); +struct timeval evTimeVal __P((struct timespec)); +int evCmpTime __P((struct timespec, struct timespec)); +int evSetTimer __P((evContext, evTimerFunc, void *, struct timespec, + struct timespec, evTimerID *)); +int evClearTimer __P((evContext, evTimerID)); +int evConfigTimer __P((evContext, evTimerID, const char *param, + int value)); +int evResetTimer __P((evContext, evTimerID, evTimerFunc, void *, + struct timespec, struct timespec)); +int evSetIdleTimer __P((evContext, evTimerFunc, void *, struct timespec, + evTimerID *)); +int evClearIdleTimer __P((evContext, evTimerID)); +int evResetIdleTimer __P((evContext, evTimerID, evTimerFunc, void *, + struct timespec)); +int evTouchIdleTimer __P((evContext, evTimerID)); + +/* ev_waits.c */ +#define evWaitFor __evWaitFor +#define evDo __evDo +#define evUnwait __evUnwait +#define evDefer __evDefer + +int evWaitFor __P((evContext, const void *, evWaitFunc, void *, evWaitID *)); +int evDo __P((evContext, const void *)); +int evUnwait __P((evContext, evWaitID)); +int evDefer __P((evContext, evWaitFunc, void *)); + +#ifdef __EVENTLIB_P_DEFINED +# undef __P +#endif + +#endif /*_EVENTLIB_H*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/include/isc/heap.h b/contrib/bind-9.5.2/lib/bind/include/isc/heap.h new file mode 100644 index 0000000000..384d507cf5 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/isc/heap.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1997,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +typedef int (*heap_higher_priority_func)(void *, void *); +typedef void (*heap_index_func)(void *, int); +typedef void (*heap_for_each_func)(void *, void *); + +typedef struct heap_context { + int array_size; + int array_size_increment; + int heap_size; + void **heap; + heap_higher_priority_func higher_priority; + heap_index_func index; +} *heap_context; + +#define heap_new __heap_new +#define heap_free __heap_free +#define heap_insert __heap_insert +#define heap_delete __heap_delete +#define heap_increased __heap_increased +#define heap_decreased __heap_decreased +#define heap_element __heap_element +#define heap_for_each __heap_for_each + +heap_context heap_new(heap_higher_priority_func, heap_index_func, int); +int heap_free(heap_context); +int heap_insert(heap_context, void *); +int heap_delete(heap_context, int); +int heap_increased(heap_context, int); +int heap_decreased(heap_context, int); +void * heap_element(heap_context, int); +int heap_for_each(heap_context, heap_for_each_func, void *); + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/include/isc/irpmarshall.h b/contrib/bind-9.5.2/lib/bind/include/isc/irpmarshall.h new file mode 100644 index 0000000000..244b3e3460 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/isc/irpmarshall.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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: irpmarshall.h,v 1.4 2005/04/27 04:56:17 sra Exp $ + */ + +#ifndef _IRPMARSHALL_H_INCLUDED +#define _IRPMARSHALL_H_INCLUDED + +/* Hide function names */ +#define irp_marshall_gr __irp_marshall_gr +#define irp_marshall_ho __irp_marshall_ho +#define irp_marshall_ne __irp_marshall_ne +#define irp_marshall_ng __irp_marshall_ng +#define irp_marshall_nw __irp_marshall_nw +#define irp_marshall_pr __irp_marshall_pr +#define irp_marshall_pw __irp_marshall_pw +#define irp_marshall_sv __irp_marshall_sv +#define irp_unmarshall_gr __irp_unmarshall_gr +#define irp_unmarshall_ho __irp_unmarshall_ho +#define irp_unmarshall_ne __irp_unmarshall_ne +#define irp_unmarshall_ng __irp_unmarshall_ng +#define irp_unmarshall_nw __irp_unmarshall_nw +#define irp_unmarshall_pr __irp_unmarshall_pr +#define irp_unmarshall_pw __irp_unmarshall_pw +#define irp_unmarshall_sv __irp_unmarshall_sv + +#define MAXPADDRSIZE (sizeof "255.255.255.255" + 1) +#define ADDR_T_STR(x) (x == AF_INET ? "AF_INET" :\ + (x == AF_INET6 ? "AF_INET6" : "UNKNOWN")) + +/* See comment below on usage */ +int irp_marshall_pw(const struct passwd *, char **, size_t *); +int irp_unmarshall_pw(struct passwd *, char *); +int irp_marshall_gr(const struct group *, char **, size_t *); +int irp_unmarshall_gr(struct group *, char *); +int irp_marshall_sv(const struct servent *, char **, size_t *); +int irp_unmarshall_sv(struct servent *, char *); +int irp_marshall_pr(struct protoent *, char **, size_t *); +int irp_unmarshall_pr(struct protoent *, char *); +int irp_marshall_ho(struct hostent *, char **, size_t *); +int irp_unmarshall_ho(struct hostent *, char *); +int irp_marshall_ng(const char *, const char *, const char *, + char **, size_t *); +int irp_unmarshall_ng(const char **, const char **, const char **, char *); +int irp_marshall_nw(struct nwent *, char **, size_t *); +int irp_unmarshall_nw(struct nwent *, char *); +int irp_marshall_ne(struct netent *, char **, size_t *); +int irp_unmarshall_ne(struct netent *, char *); + +/*! \file + * \brief + * Functions to marshall and unmarshall various system data structures. We + * use a printable ascii format that is as close to various system config + * files as reasonable (e.g. /etc/passwd format). + * + * We are not forgiving with unmarhsalling misformatted buffers. In + * particular whitespace in fields is not ignored. So a formatted password + * entry "brister :1364:100:...." will yield a username of "brister " + * + * We potentially do a lot of mallocs to fill fields that are of type + * (char **) like a hostent h_addr field. Building (for example) the + * h_addr field and its associated addresses all in one buffer is + * certainly possible, but not done here. + * + * The following description is true for all the marshalling functions: + * + * int irp_marshall_XX(struct yyyy *XX, char **buffer, size_t *len); + * + * The argument XX (of type struct passwd for example) is marshalled in the + * buffer pointed at by *BUFFER, which is of length *LEN. Returns 0 + * on success and -1 on failure. Failure will occur if *LEN is + * smaller than needed. + * + * If BUFFER is NULL, then *LEN is set to the size of the buffer + * needed to marshall the data and no marshalling is actually done. + * + * If *BUFFER is NULL, then a buffer large enough will be allocated + * with memget() and the size allocated will be stored in *LEN. An extra 2 + * bytes will be allocated for the client to append CRLF if wanted. The + * value of *LEN will include these two bytes. + * + * All the marshalling functions produce a buffer with the fields + * separated by colons (except for the hostent marshalling, which uses '@' + * to separate fields). Fields that have multiple subfields (like the + * gr_mem field in struct group) have their subparts separated by + * commas. + * + * int irp_unmarshall_XX(struct YYYYY *XX, char *buffer); + * + * The unmashalling functions break apart the buffer and store the + * values in the struct pointed to by XX. All pointer values inside + * XX are allocated with malloc. All arrays of pointers have a NULL + * as the last element. + */ + +#endif diff --git a/contrib/bind-9.5.2/lib/bind/include/isc/list.h b/contrib/bind-9.5.2/lib/bind/include/isc/list.h new file mode 100644 index 0000000000..c85c6676b5 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/isc/list.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1997,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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 LIST_H +#define LIST_H 1 +#include + +#define LIST(type) struct { type *head, *tail; } +#define INIT_LIST(list) \ + do { (list).head = NULL; (list).tail = NULL; } while (0) + +#define LINK(type) struct { type *prev, *next; } +#define INIT_LINK_TYPE(elt, link, type) \ + do { \ + (elt)->link.prev = (type *)(-1); \ + (elt)->link.next = (type *)(-1); \ + } while (0) +#define INIT_LINK(elt, link) \ + INIT_LINK_TYPE(elt, link, void) +#define LINKED(elt, link) ((void *)((elt)->link.prev) != (void *)(-1)) + +#define HEAD(list) ((list).head) +#define TAIL(list) ((list).tail) +#define EMPTY(list) ((list).head == NULL) + +#define PREPEND(list, elt, link) \ + do { \ + INSIST(!LINKED(elt, link));\ + if ((list).head != NULL) \ + (list).head->link.prev = (elt); \ + else \ + (list).tail = (elt); \ + (elt)->link.prev = NULL; \ + (elt)->link.next = (list).head; \ + (list).head = (elt); \ + } while (0) + +#define APPEND(list, elt, link) \ + do { \ + INSIST(!LINKED(elt, link));\ + if ((list).tail != NULL) \ + (list).tail->link.next = (elt); \ + else \ + (list).head = (elt); \ + (elt)->link.prev = (list).tail; \ + (elt)->link.next = NULL; \ + (list).tail = (elt); \ + } while (0) + +#define UNLINK_TYPE(list, elt, link, type) \ + do { \ + INSIST(LINKED(elt, link));\ + if ((elt)->link.next != NULL) \ + (elt)->link.next->link.prev = (elt)->link.prev; \ + else { \ + INSIST((list).tail == (elt)); \ + (list).tail = (elt)->link.prev; \ + } \ + if ((elt)->link.prev != NULL) \ + (elt)->link.prev->link.next = (elt)->link.next; \ + else { \ + INSIST((list).head == (elt)); \ + (list).head = (elt)->link.next; \ + } \ + INIT_LINK_TYPE(elt, link, type); \ + } while (0) +#define UNLINK(list, elt, link) \ + UNLINK_TYPE(list, elt, link, void) + +#define PREV(elt, link) ((elt)->link.prev) +#define NEXT(elt, link) ((elt)->link.next) + +#define INSERT_BEFORE(list, before, elt, link) \ + do { \ + INSIST(!LINKED(elt, link));\ + if ((before)->link.prev == NULL) \ + PREPEND(list, elt, link); \ + else { \ + (elt)->link.prev = (before)->link.prev; \ + (before)->link.prev = (elt); \ + (elt)->link.prev->link.next = (elt); \ + (elt)->link.next = (before); \ + } \ + } while (0) + +#define INSERT_AFTER(list, after, elt, link) \ + do { \ + INSIST(!LINKED(elt, link));\ + if ((after)->link.next == NULL) \ + APPEND(list, elt, link); \ + else { \ + (elt)->link.next = (after)->link.next; \ + (after)->link.next = (elt); \ + (elt)->link.next->link.prev = (elt); \ + (elt)->link.prev = (after); \ + } \ + } while (0) + +#define ENQUEUE(list, elt, link) APPEND(list, elt, link) +#define DEQUEUE(list, elt, link) UNLINK(list, elt, link) + +#endif /* LIST_H */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/include/isc/logging.h b/contrib/bind-9.5.2/lib/bind/include/isc/logging.h new file mode 100644 index 0000000000..c539443ff8 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/isc/logging.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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 LOGGING_H +#define LOGGING_H + +#include +#include +#include +#include + +#define log_critical (-5) +#define log_error (-4) +#define log_warning (-3) +#define log_notice (-2) +#define log_info (-1) +#define log_debug(level) (level) + +typedef enum { log_syslog, log_file, log_null } log_channel_type; + +#define LOG_MAX_VERSIONS 99 + +#define LOG_CLOSE_STREAM 0x0001 +#define LOG_TIMESTAMP 0x0002 +#define LOG_TRUNCATE 0x0004 +#define LOG_USE_CONTEXT_LEVEL 0x0008 +#define LOG_PRINT_LEVEL 0x0010 +#define LOG_REQUIRE_DEBUG 0x0020 +#define LOG_CHANNEL_BROKEN 0x0040 +#define LOG_PRINT_CATEGORY 0x0080 +#define LOG_CHANNEL_OFF 0x0100 + +typedef struct log_context *log_context; +typedef struct log_channel *log_channel; + +#define LOG_OPTION_DEBUG 0x01 +#define LOG_OPTION_LEVEL 0x02 + +#define log_open_stream __log_open_stream +#define log_close_stream __log_close_stream +#define log_get_stream __log_get_stream +#define log_get_filename __log_get_filename +#define log_check_channel __log_check_channel +#define log_check __log_check +#define log_vwrite __log_vwrite +#define log_write __log_write +#define log_new_context __log_new_context +#define log_free_context __log_free_context +#define log_add_channel __log_add_channel +#define log_remove_channel __log_remove_channel +#define log_option __log_option +#define log_category_is_active __log_category_is_active +#define log_new_syslog_channel __log_new_syslog_channel +#define log_new_file_channel __log_new_file_channel +#define log_set_file_owner __log_set_file_owner +#define log_new_null_channel __log_new_null_channel +#define log_inc_references __log_inc_references +#define log_dec_references __log_dec_references +#define log_get_channel_type __log_get_channel_type +#define log_free_channel __log_free_channel +#define log_close_debug_channels __log_close_debug_channels + +FILE * log_open_stream(log_channel); +int log_close_stream(log_channel); +FILE * log_get_stream(log_channel); +char * log_get_filename(log_channel); +int log_check_channel(log_context, int, log_channel); +int log_check(log_context, int, int); +#ifdef __GNUC__ +void log_vwrite(log_context, int, int, const char *, + va_list args) + __attribute__((__format__(__printf__, 4, 0))); +void log_write(log_context, int, int, const char *, ...) + __attribute__((__format__(__printf__, 4, 5))); +#else +void log_vwrite(log_context, int, int, const char *, + va_list args); +void log_write(log_context, int, int, const char *, ...); +#endif +int log_new_context(int, char **, log_context *); +void log_free_context(log_context); +int log_add_channel(log_context, int, log_channel); +int log_remove_channel(log_context, int, log_channel); +int log_option(log_context, int, int); +int log_category_is_active(log_context, int); +log_channel log_new_syslog_channel(unsigned int, int, int); +log_channel log_new_file_channel(unsigned int, int, const char *, + FILE *, unsigned int, + unsigned long); +int log_set_file_owner(log_channel, uid_t, gid_t); +log_channel log_new_null_channel(void); +int log_inc_references(log_channel); +int log_dec_references(log_channel); +log_channel_type log_get_channel_type(log_channel); +int log_free_channel(log_channel); +void log_close_debug_channels(log_context); + +#endif /* !LOGGING_H */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/include/isc/memcluster.h b/contrib/bind-9.5.2/lib/bind/include/isc/memcluster.h new file mode 100644 index 0000000000..0923deb5e7 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/isc/memcluster.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1997,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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 MEMCLUSTER_H +#define MEMCLUSTER_H + +#include + +#define meminit __meminit +#ifdef MEMCLUSTER_DEBUG +#define memget(s) __memget_debug(s, __FILE__, __LINE__) +#define memput(p, s) __memput_debug(p, s, __FILE__, __LINE__) +#else /*MEMCLUSTER_DEBUG*/ +#ifdef MEMCLUSTER_RECORD +#define memget(s) __memget_record(s, __FILE__, __LINE__) +#define memput(p, s) __memput_record(p, s, __FILE__, __LINE__) +#else /*MEMCLUSTER_RECORD*/ +#define memget __memget +#define memput __memput +#endif /*MEMCLUSTER_RECORD*/ +#endif /*MEMCLUSTER_DEBUG*/ +#define memstats __memstats +#define memactive __memactive + +int meminit(size_t, size_t); +void * __memget(size_t); +void __memput(void *, size_t); +void * __memget_debug(size_t, const char *, int); +void __memput_debug(void *, size_t, const char *, int); +void * __memget_record(size_t, const char *, int); +void __memput_record(void *, size_t, const char *, int); +void memstats(FILE *); +int memactive(void); + +#endif /* MEMCLUSTER_H */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/include/isc/misc.h b/contrib/bind-9.5.2/lib/bind/include/isc/misc.h new file mode 100644 index 0000000000..8736bf91ed --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/isc/misc.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1995-1999 by Internet Software Consortium + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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: misc.h,v 1.5.672.1 2008/02/18 04:10:16 marka Exp $ + */ + +#ifndef _ISC_MISC_H +#define _ISC_MISC_H + +/*! \file */ + +#include +#include + +#define bitncmp __bitncmp +/*#define isc_movefile __isc_movefile */ + +extern int bitncmp(const void *, const void *, int); +extern int isc_movefile(const char *, const char *); + +extern int isc_gethexstring(unsigned char *, size_t, int, FILE *, + int *); +extern void isc_puthexstring(FILE *, const unsigned char *, size_t, + size_t, size_t, const char *); +extern void isc_tohex(const unsigned char *, size_t, char *); + +#endif /*_ISC_MISC_H*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/include/isc/platform.h.in b/contrib/bind-9.5.2/lib/bind/include/isc/platform.h.in new file mode 100644 index 0000000000..6144a5353f --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/isc/platform.h.in @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2008 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.2.2.2 2008/01/23 02:15:32 tbox Exp $ */ + +/*! \file */ + +#ifndef ISC_PLATFORM_H +#define ISC_PLATFORM_H + +/* + * Define if the OS does not define struct timespec. + */ +@ISC_PLATFORM_NEEDTIMESPEC@ +#ifdef ISC_PLATFORM_NEEDTIMESPEC +#include /* For time_t */ +struct timespec { + time_t tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ +}; +#endif + +#endif diff --git a/contrib/bind-9.5.2/lib/bind/include/isc/tree.h b/contrib/bind-9.5.2/lib/bind/include/isc/tree.h new file mode 100644 index 0000000000..96feaca68d --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/isc/tree.h @@ -0,0 +1,59 @@ +/* tree.h - declare structures used by tree library + * + * vix 22jan93 [revisited; uses RCS, ANSI, POSIX; has bug fixes] + * vix 27jun86 [broken out of tree.c] + * + * $Id: tree.h,v 1.3 2005/04/27 04:56:18 sra Exp $ + */ + + +#ifndef _TREE_H_INCLUDED +#define _TREE_H_INCLUDED + + +#ifndef __P +# if defined(__STDC__) || defined(__GNUC__) +# define __P(x) x +# else +# define __P(x) () +# endif +#endif + +/*% + * tree_t is our package-specific anonymous pointer. + */ +#if defined(__STDC__) || defined(__GNUC__) +typedef void *tree_t; +#else +typedef char *tree_t; +#endif + +/*% + * Do not taint namespace + */ +#define tree_add __tree_add +#define tree_delete __tree_delete +#define tree_init __tree_init +#define tree_mung __tree_mung +#define tree_srch __tree_srch +#define tree_trav __tree_trav + + +typedef struct tree_s { + tree_t data; + struct tree_s *left, *right; + short bal; + } + tree; + + +void tree_init __P((tree **)); +tree_t tree_srch __P((tree **, int (*)(), tree_t)); +tree_t tree_add __P((tree **, int (*)(), tree_t, void (*)())); +int tree_delete __P((tree **, int (*)(), tree_t, void (*)())); +int tree_trav __P((tree **, int (*)())); +void tree_mung __P((tree **, void (*)())); + + +#endif /* _TREE_H_INCLUDED */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/include/netdb.h b/contrib/bind-9.5.2/lib/bind/include/netdb.h new file mode 100644 index 0000000000..651cdd87db --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/netdb.h @@ -0,0 +1,582 @@ +/* + * ++Copyright++ 1980, 1983, 1988, 1993 + * - + * Copyright (c) 1980, 1983, 1988, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION 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. + * - + * Portions 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by WIDE Project and + * its contributors. + * 4. 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. + * - + * --Copyright-- + */ + +/* + * @(#)netdb.h 8.1 (Berkeley) 6/2/93 + * $Id: netdb.h,v 1.21.288.1 2008/02/28 05:46:12 marka Exp $ + */ + +#ifndef _NETDB_H_ +#define _NETDB_H_ + +#include +#include +#if (!defined(BSD)) || (BSD < 199306) +# include +#endif +#include +#include +#include +#include + +#ifndef _PATH_HEQUIV +#define _PATH_HEQUIV "/etc/hosts.equiv" +#endif +#ifndef _PATH_HOSTS +#define _PATH_HOSTS "/etc/hosts" +#endif +#ifndef _PATH_NETWORKS +#define _PATH_NETWORKS "/etc/networks" +#endif +#ifndef _PATH_PROTOCOLS +#define _PATH_PROTOCOLS "/etc/protocols" +#endif +#ifndef _PATH_SERVICES +#define _PATH_SERVICES "/etc/services" +#endif + +#if (__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) +#define __h_errno __h_errno_location +#endif +__BEGIN_DECLS +extern int * __h_errno __P((void)); +__END_DECLS +#if defined(_REENTRANT) || \ + (__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) +#define h_errno (*__h_errno()) +#else +extern int h_errno; +#endif + +/*% + * Structures returned by network data base library. All addresses are + * supplied in host order, and returned in network order (suitable for + * use in system calls). + */ +struct hostent { + char *h_name; /*%< official name of host */ + char **h_aliases; /*%< alias list */ + int h_addrtype; /*%< host address type */ + int h_length; /*%< length of address */ + char **h_addr_list; /*%< list of addresses from name server */ +#define h_addr h_addr_list[0] /*%< address, for backward compatiblity */ +}; + +/*% + * Assumption here is that a network number + * fits in an unsigned long -- probably a poor one. + */ +struct netent { + char *n_name; /*%< official name of net */ + char **n_aliases; /*%< alias list */ + int n_addrtype; /*%< net address type */ + unsigned long n_net; /*%< network # */ +}; + +struct servent { + char *s_name; /*%< official service name */ + char **s_aliases; /*%< alias list */ + int s_port; /*%< port # */ + char *s_proto; /*%< protocol to use */ +}; + +struct protoent { + char *p_name; /*%< official protocol name */ + char **p_aliases; /*%< alias list */ + int p_proto; /*%< protocol # */ +}; + +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 */ +#if defined(sun) && defined(_SOCKLEN_T) +#ifdef __sparcv9 + int _ai_pad; +#endif + socklen_t ai_addrlen; +#else + size_t ai_addrlen; /*%< length of ai_addr */ +#endif +#ifdef __linux + struct sockaddr *ai_addr; /*%< binary address */ + char *ai_canonname; /*%< canonical name for hostname */ +#else + char *ai_canonname; /*%< canonical name for hostname */ + struct sockaddr *ai_addr; /*%< binary address */ +#endif + struct addrinfo *ai_next; /*%< next structure in linked list */ +}; + +/*% + * Error return codes from gethostbyname() and gethostbyaddr() + * (left in extern int h_errno). + */ + +#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() + */ +#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_MAX 14 + +/*% + * Flag values for getaddrinfo() + */ +#define AI_PASSIVE 0x00000001 +#define AI_CANONNAME 0x00000002 +#define AI_NUMERICHOST 0x00000004 +#define AI_MASK 0x00000007 + +/*% + * Flag values for getipnodebyname() + */ +#define AI_V4MAPPED 0x00000008 +#define AI_ALL 0x00000010 +#define AI_ADDRCONFIG 0x00000020 +#define AI_DEFAULT (AI_V4MAPPED|AI_ADDRCONFIG) + +/*% + * Constants for getnameinfo() + */ +#define NI_MAXHOST 1025 +#define NI_MAXSERV 32 + +/*% + * Flag values for getnameinfo() + */ +#define NI_NOFQDN 0x00000001 +#define NI_NUMERICHOST 0x00000002 +#define NI_NAMEREQD 0x00000004 +#define NI_NUMERICSERV 0x00000008 +#define NI_DGRAM 0x00000010 +#define NI_WITHSCOPEID 0x00000020 +#define NI_NUMERICSCOPE 0x00000040 + +/*% + * Scope delimit character + */ +#define SCOPE_DELIMITER '%' + + +#ifdef _REENTRANT +#if defined (__hpux) || defined(__osf__) || defined(_AIX) +#define _MAXALIASES 35 +#define _MAXLINELEN 1024 +#define _MAXADDRS 35 +#define _HOSTBUFSIZE (BUFSIZ + 1) + +struct hostent_data { + struct in_addr host_addr; + char *h_addr_ptrs[_MAXADDRS + 1]; + char hostaddr[_MAXADDRS]; + char hostbuf[_HOSTBUFSIZE]; + char *host_aliases[_MAXALIASES]; + char *host_addrs[2]; + FILE *hostf; +#ifdef __osf__ + int svc_gethostflag; + int svc_gethostbind; +#endif +#ifdef __hpux + short _nsw_src; + short _flags; + char *current; + int currentlen; +#endif +}; + +struct netent_data { + FILE *net_fp; +#if defined(__osf__) || defined(_AIX) + char line[_MAXLINELEN]; +#endif +#ifdef __hpux + char line[_MAXLINELEN+1]; +#endif + char *net_aliases[_MAXALIASES]; +#ifdef __osf__ + int _net_stayopen; + int svc_getnetflag; +#endif +#ifdef __hpux + short _nsw_src; + short _flags; + char *current; + int currentlen; +#endif +#ifdef _AIX + int _net_stayopen; + char *current; + int currentlen; + void *_net_reserv1; /* reserved for future use */ + void *_net_reserv2; /* reserved for future use */ +#endif +}; + +struct protoent_data { + FILE *proto_fp; +#ifdef _AIX + int _proto_stayopen; + char line[_MAXLINELEN]; +#endif +#ifdef __osf__ + char line[1024]; +#endif +#ifdef __hpux + char line[_MAXLINELEN+1]; +#endif + char *proto_aliases[_MAXALIASES]; +#ifdef __osf__ + int _proto_stayopen; + int svc_getprotoflag; +#endif +#ifdef __hpux + short _nsw_src; + short _flags; + char *current; + int currentlen; +#endif +#ifdef _AIX + int currentlen; + char *current; + void *_proto_reserv1; /* reserved for future use */ + void *_proto_reserv2; /* reserved for future use */ +#endif +}; + +struct servent_data { + FILE *serv_fp; +#if defined(__osf__) || defined(_AIX) + char line[_MAXLINELEN]; +#endif +#ifdef __hpux + char line[_MAXLINELEN+1]; +#endif + char *serv_aliases[_MAXALIASES]; +#ifdef __osf__ + int _serv_stayopen; + int svc_getservflag; +#endif +#ifdef __hpux + short _nsw_src; + short _flags; + char *current; + int currentlen; +#endif +#ifdef _AIX + int _serv_stayopen; + char *current; + int currentlen; + void *_serv_reserv1; /* reserved for future use */ + void *_serv_reserv2; /* reserved for future use */ +#endif +}; +#endif +#endif +__BEGIN_DECLS +void endhostent __P((void)); +void endnetent __P((void)); +void endprotoent __P((void)); +void endservent __P((void)); +void freehostent __P((struct hostent *)); +struct hostent *gethostbyaddr __P((const char *, int, int)); +struct hostent *gethostbyname __P((const char *)); +struct hostent *gethostbyname2 __P((const char *, int)); +struct hostent *gethostent __P((void)); +struct hostent *getipnodebyaddr __P((const void *, size_t, int, int *)); +struct hostent *getipnodebyname __P((const char *, int, int, int *)); +struct netent *getnetbyaddr __P((unsigned long, int)); +struct netent *getnetbyname __P((const char *)); +struct netent *getnetent __P((void)); +struct protoent *getprotobyname __P((const char *)); +struct protoent *getprotobynumber __P((int)); +struct protoent *getprotoent __P((void)); +struct servent *getservbyname __P((const char *, const char *)); +struct servent *getservbyport __P((int, const char *)); +struct servent *getservent __P((void)); +void herror __P((const char *)); +const char *hstrerror __P((int)); +void sethostent __P((int)); +/* void sethostfile __P((const char *)); */ +void setnetent __P((int)); +void setprotoent __P((int)); +void setservent __P((int)); +int getaddrinfo __P((const char *, const char *, + const struct addrinfo *, struct addrinfo **)); +int getnameinfo __P((const struct sockaddr *, size_t, char *, + size_t, char *, size_t, int)); +void freeaddrinfo __P((struct addrinfo *)); +const char *gai_strerror __P((int)); +struct hostent *getipnodebyname __P((const char *, int, int, int *)); +struct hostent *getipnodebyaddr __P((const void *, size_t, int, int *)); +void freehostent __P((struct hostent *)); +#ifdef __GLIBC__ +int getnetgrent __P((/* const */ char **, /* const */ char **, + /* const */ char **)); +void setnetgrent __P((const char *)); +void endnetgrent __P((void)); +int innetgr __P((const char *, const char *, const char *, + const char *)); +#endif + +#ifdef _REENTRANT +#if defined(__hpux) || defined(__osf__) || defined(_AIX) +int gethostbyaddr_r __P((const char *, int, int, struct hostent *, + struct hostent_data *)); +int gethostbyname_r __P((const char *, struct hostent *, + struct hostent_data *)); +int gethostent_r __P((struct hostent *, struct hostent_data *)); +#if defined(_AIX) +void sethostent_r __P((int, struct hostent_data *)); +#else +int sethostent_r __P((int, struct hostent_data *)); +#endif +#if defined(__hpux) +int endhostent_r __P((struct hostent_data *)); +#else +void endhostent_r __P((struct hostent_data *)); +#endif + +#if defined(__hpux) || defined(__osf__) +int getnetbyaddr_r __P((int, int, + struct netent *, struct netent_data *)); +#else +int getnetbyaddr_r __P((long, int, + struct netent *, struct netent_data *)); +#endif +int getnetbyname_r __P((const char *, + struct netent *, struct netent_data *)); +int getnetent_r __P((struct netent *, struct netent_data *)); +int setnetent_r __P((int, struct netent_data *)); +#ifdef __hpux +int endnetent_r __P((struct netent_data *buffer)); +#else +void endnetent_r __P((struct netent_data *buffer)); +#endif + +int getprotobyname_r __P((const char *, + struct protoent *, struct protoent_data *)); +int getprotobynumber_r __P((int, + struct protoent *, struct protoent_data *)); +int getprotoent_r __P((struct protoent *, struct protoent_data *)); +int setprotoent_r __P((int, struct protoent_data *)); +#ifdef __hpux +int endprotoent_r __P((struct protoent_data *)); +#else +void endprotoent_r __P((struct protoent_data *)); +#endif + +int getservbyname_r __P((const char *, const char *, + struct servent *, struct servent_data *)); +int getservbyport_r __P((int, const char *, + struct servent *, struct servent_data *)); +int getservent_r __P((struct servent *, struct servent_data *)); +int setservent_r __P((int, struct servent_data *)); +#ifdef __hpux +int endservent_r __P((struct servent_data *)); +#else +void endservent_r __P((struct servent_data *)); +#endif +#ifdef _AIX +int setnetgrent_r __P((char *, void **)); +void endnetgrent_r __P((void **)); +/* + * Note: AIX's netdb.h declares innetgr_r() as: + * int innetgr_r(char *, char *, char *, char *, struct innetgr_data *); + */ +int innetgr_r __P((const char *, const char *, const char *, + const char *)); +#endif +#else + /* defined(sun) || defined(bsdi) */ +#if defined(__GLIBC__) || defined(__FreeBSD__) && (__FreeBSD_version + 0 >= 601103) +int gethostbyaddr_r __P((const char *, int, int, struct hostent *, + char *, size_t, struct hostent **, int *)); +int gethostbyname_r __P((const char *, struct hostent *, + char *, size_t, struct hostent **, int *)); +int gethostent_r __P((struct hostent *, char *, size_t, + struct hostent **, int *)); +#else +struct hostent *gethostbyaddr_r __P((const char *, int, int, struct hostent *, + char *, int, int *)); +struct hostent *gethostbyname_r __P((const char *, struct hostent *, + char *, int, int *)); +struct hostent *gethostent_r __P((struct hostent *, char *, int, int *)); +#endif +void sethostent_r __P((int)); +void endhostent_r __P((void)); + +#if defined(__GLIBC__) || defined(__FreeBSD__) && (__FreeBSD_version + 0 >= 601103) +int getnetbyname_r __P((const char *, struct netent *, + char *, size_t, struct netent **, int*)); +int getnetbyaddr_r __P((unsigned long int, int, struct netent *, + char *, size_t, struct netent **, int*)); +int getnetent_r __P((struct netent *, char *, size_t, struct netent **, int*)); +#else +struct netent *getnetbyname_r __P((const char *, struct netent *, + char *, int)); +struct netent *getnetbyaddr_r __P((long, int, struct netent *, + char *, int)); +struct netent *getnetent_r __P((struct netent *, char *, int)); +#endif +void setnetent_r __P((int)); +void endnetent_r __P((void)); + +#if defined(__GLIBC__) || defined(__FreeBSD__) && (__FreeBSD_version + 0 >= 601103) +int getprotobyname_r __P((const char *, struct protoent *, char *, + size_t, struct protoent **)); +int getprotobynumber_r __P((int, struct protoent *, char *, size_t, + struct protoent **)); +int getprotoent_r __P((struct protoent *, char *, size_t, struct protoent **)); +#else +struct protoent *getprotobyname_r __P((const char *, + struct protoent *, char *, int)); +struct protoent *getprotobynumber_r __P((int, + struct protoent *, char *, int)); +struct protoent *getprotoent_r __P((struct protoent *, char *, int)); +#endif +void setprotoent_r __P((int)); +void endprotoent_r __P((void)); + +#if defined(__GLIBC__) || defined(__FreeBSD__) && (__FreeBSD_version + 0 >= 601103) +int getservbyname_r __P((const char *name, const char *, + struct servent *, char *, size_t, struct servent **)); +int getservbyport_r __P((int port, const char *, + struct servent *, char *, size_t, struct servent **)); +int getservent_r __P((struct servent *, char *, size_t, struct servent **)); +#else +struct servent *getservbyname_r __P((const char *name, const char *, + struct servent *, char *, int)); +struct servent *getservbyport_r __P((int port, const char *, + struct servent *, char *, int)); +struct servent *getservent_r __P((struct servent *, char *, int)); +#endif +void setservent_r __P((int)); +void endservent_r __P((void)); + +#ifdef __GLIBC__ +int getnetgrent_r __P((char **, char **, char **, char *, size_t)); +#endif + +#endif +#endif +__END_DECLS + +/* This is nec'y to make this include file properly replace the sun version. */ +#ifdef sun +#ifdef __GNU_LIBRARY__ +#include +#else +struct rpcent { + char *r_name; /*%< name of server for this rpc program */ + char **r_aliases; /*%< alias list */ + int r_number; /*%< rpc program number */ +}; +struct rpcent *getrpcbyname(), *getrpcbynumber(), *getrpcent(); +#endif /* __GNU_LIBRARY__ */ +#endif /* sun */ +#endif /* !_NETDB_H_ */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/include/netgroup.h b/contrib/bind-9.5.2/lib/bind/include/netgroup.h new file mode 100644 index 0000000000..e4be459fdf --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/netgroup.h @@ -0,0 +1,26 @@ +#ifndef netgroup_h +#define netgroup_h +#ifndef __GLIBC__ + +/* + * The standard is crazy. These values "belong" to getnetgrent() and + * shouldn't be altered by the caller. + */ +int getnetgrent __P((/* const */ char **, /* const */ char **, + /* const */ char **)); + +int getnetgrent_r __P((char **, char **, char **, char *, int)); + +void endnetgrent __P((void)); + +#ifdef __osf__ +int innetgr __P((char *, char *, char *, char *)); +void setnetgrent __P((char *)); +#else +void setnetgrent __P((const char *)); +int innetgr __P((const char *, const char *, const char *, const char *)); +#endif +#endif +#endif + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/include/res_update.h b/contrib/bind-9.5.2/lib/bind/include/res_update.h new file mode 100644 index 0000000000..d6cbabc34c --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/res_update.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1999 by Internet Software Consortium, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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: res_update.h,v 1.3 2005/04/27 04:56:15 sra Exp $ + */ + +#ifndef __RES_UPDATE_H +#define __RES_UPDATE_H + +/*! \file */ + +#include +#include +#include +#include + +/*% + * This RR-like structure is particular to UPDATE. + */ +struct ns_updrec { + LINK(struct ns_updrec) r_link, r_glink; + ns_sect r_section; /*%< ZONE/PREREQUISITE/UPDATE */ + char * r_dname; /*%< owner of the RR */ + ns_class r_class; /*%< class number */ + ns_type r_type; /*%< type number */ + u_int32_t r_ttl; /*%< time to live */ + u_char * r_data; /*%< rdata fields as text string */ + u_int r_size; /*%< size of r_data field */ + int r_opcode; /*%< type of operation */ + /* following fields for private use by the resolver/server routines */ + struct databuf *r_dp; /*%< databuf to process */ + struct databuf *r_deldp; /*%< databuf's deleted/overwritten */ + u_int r_zone; /*%< zone number on server */ +}; +typedef struct ns_updrec ns_updrec; +typedef LIST(ns_updrec) ns_updque; + +#define res_mkupdate __res_mkupdate +#define res_update __res_update +#define res_mkupdrec __res_mkupdrec +#define res_freeupdrec __res_freeupdrec +#define res_nmkupdate __res_nmkupdate +#define res_nupdate __res_nupdate + +int res_mkupdate __P((ns_updrec *, u_char *, int)); +int res_update __P((ns_updrec *)); +ns_updrec * res_mkupdrec __P((int, const char *, u_int, u_int, u_long)); +void res_freeupdrec __P((ns_updrec *)); +int res_nmkupdate __P((res_state, ns_updrec *, u_char *, int)); +int res_nupdate __P((res_state, ns_updrec *, ns_tsig_key *)); + +#endif /*__RES_UPDATE_H*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/include/resolv.h b/contrib/bind-9.5.2/lib/bind/include/resolv.h new file mode 100644 index 0000000000..409a48818d --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/resolv.h @@ -0,0 +1,509 @@ +/* + * Copyright (c) 1983, 1987, 1989 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +/*% + * @(#)resolv.h 8.1 (Berkeley) 6/2/93 + * $Id: resolv.h,v 1.23.564.1 2008/04/03 02:12:21 marka Exp $ + */ + +#ifndef _RESOLV_H_ +#define _RESOLV_H_ + +#include +#if (!defined(BSD)) || (BSD < 199306) +# include +#else +# include +#endif +#include +#include +#include +#include + +/*% + * Revision information. This is the release date in YYYYMMDD format. + * It can change every day so the right thing to do with it is use it + * in preprocessor commands such as "#if (__RES > 19931104)". Do not + * compare for equality; rather, use it to determine whether your resolver + * is new enough to contain a certain feature. + */ + +#define __RES 20030124 + +/*% + * This used to be defined in res_query.c, now it's in herror.c. + * [XXX no it's not. It's in irs/irs_data.c] + * It was + * never extern'd by any *.h file before it was placed here. For thread + * aware programs, the last h_errno value set is stored in res->h_errno. + * + * XXX: There doesn't seem to be a good reason for exposing RES_SET_H_ERRNO + * (and __h_errno_set) to the public via . + * XXX: __h_errno_set is really part of IRS, not part of the resolver. + * If somebody wants to build and use a resolver that doesn't use IRS, + * what do they do? Perhaps something like + * #ifdef WANT_IRS + * # define RES_SET_H_ERRNO(r,x) __h_errno_set(r,x) + * #else + * # define RES_SET_H_ERRNO(r,x) (h_errno = (r)->res_h_errno = (x)) + * #endif + */ + +#define RES_SET_H_ERRNO(r,x) __h_errno_set(r,x) +struct __res_state; /*%< forward */ +__BEGIN_DECLS +void __h_errno_set(struct __res_state *res, int err); +__END_DECLS + +/*% + * Resolver configuration file. + * Normally not present, but may contain the address of the + * initial name server(s) to query and the domain search list. + */ + +#ifndef _PATH_RESCONF +#define _PATH_RESCONF "/etc/resolv.conf" +#endif + +typedef enum { res_goahead, res_nextns, res_modified, res_done, res_error } + res_sendhookact; + +#ifndef __PMT +#if defined(__STDC__) || defined(__cplusplus) +#define __PMT(args) args +#else +#define __PMT(args) () +#endif +#endif + +typedef res_sendhookact (*res_send_qhook)__PMT((struct sockaddr * const *, + const u_char **, int *, + u_char *, int, int *)); + +typedef res_sendhookact (*res_send_rhook)__PMT((const struct sockaddr *, + const u_char *, int, u_char *, + int, int *)); + +struct res_sym { + int number; /*%< Identifying number, like T_MX */ + const char * name; /*%< Its symbolic name, like "MX" */ + const char * humanname; /*%< Its fun name, like "mail exchanger" */ +}; + +/*% + * Global defines and variables for resolver stub. + */ +#define MAXNS 3 /*%< max # name servers we'll track */ +#define MAXDFLSRCH 3 /*%< # default domain levels to try */ +#define MAXDNSRCH 6 /*%< max # domains in search path */ +#define LOCALDOMAINPARTS 2 /*%< min levels in name that is "local" */ +#define RES_TIMEOUT 5 /*%< min. seconds between retries */ +#define MAXRESOLVSORT 10 /*%< number of net to sort on */ +#define RES_MAXNDOTS 15 /*%< should reflect bit field size */ +#define RES_MAXRETRANS 30 /*%< only for resolv.conf/RES_OPTIONS */ +#define RES_MAXRETRY 5 /*%< only for resolv.conf/RES_OPTIONS */ +#define RES_DFLRETRY 2 /*%< Default #/tries. */ +#define RES_MAXTIME 65535 /*%< Infinity, in milliseconds. */ +struct __res_state_ext; + +struct __res_state { + int retrans; /*%< retransmission time interval */ + int retry; /*%< number of times to retransmit */ +#ifdef sun + u_int options; /*%< option flags - see below. */ +#else + u_long options; /*%< option flags - see below. */ +#endif + int nscount; /*%< number of name servers */ + struct sockaddr_in + nsaddr_list[MAXNS]; /*%< address of name server */ +#define nsaddr nsaddr_list[0] /*%< for backward compatibility */ + u_short id; /*%< current message id */ + char *dnsrch[MAXDNSRCH+1]; /*%< components of domain to search */ + char defdname[256]; /*%< default domain (deprecated) */ +#ifdef sun + u_int pfcode; /*%< RES_PRF_ flags - see below. */ +#else + u_long pfcode; /*%< RES_PRF_ flags - see below. */ +#endif + unsigned ndots:4; /*%< threshold for initial abs. query */ + unsigned nsort:4; /*%< number of elements in sort_list[] */ + char unused[3]; + struct { + struct in_addr addr; + u_int32_t mask; + } sort_list[MAXRESOLVSORT]; + res_send_qhook qhook; /*%< query hook */ + res_send_rhook rhook; /*%< response hook */ + int res_h_errno; /*%< last one set for this context */ + int _vcsock; /*%< PRIVATE: for res_send VC i/o */ + u_int _flags; /*%< PRIVATE: see below */ + u_int _pad; /*%< make _u 64 bit aligned */ + union { + /* On an 32-bit arch this means 512b total. */ + char pad[72 - 4*sizeof (int) - 2*sizeof (void *)]; + struct { + u_int16_t nscount; + u_int16_t nstimes[MAXNS]; /*%< ms. */ + int nssocks[MAXNS]; + struct __res_state_ext *ext; /*%< extention for IPv6 */ + } _ext; + } _u; +}; + +typedef struct __res_state *res_state; + +union res_sockaddr_union { + struct sockaddr_in sin; +#ifdef IN6ADDR_ANY_INIT + struct sockaddr_in6 sin6; +#endif +#ifdef ISC_ALIGN64 + int64_t __align64; /*%< 64bit alignment */ +#else + int32_t __align32; /*%< 32bit alignment */ +#endif + char __space[128]; /*%< max size */ +}; + +/*% + * Resolver flags (used to be discrete per-module statics ints). + */ +#define RES_F_VC 0x00000001 /*%< socket is TCP */ +#define RES_F_CONN 0x00000002 /*%< socket is connected */ +#define RES_F_EDNS0ERR 0x00000004 /*%< EDNS0 caused errors */ +#define RES_F__UNUSED 0x00000008 /*%< (unused) */ +#define RES_F_LASTMASK 0x000000F0 /*%< ordinal server of last res_nsend */ +#define RES_F_LASTSHIFT 4 /*%< bit position of LASTMASK "flag" */ +#define RES_GETLAST(res) (((res)._flags & RES_F_LASTMASK) >> RES_F_LASTSHIFT) + +/* res_findzonecut2() options */ +#define RES_EXHAUSTIVE 0x00000001 /*%< always do all queries */ +#define RES_IPV4ONLY 0x00000002 /*%< IPv4 only */ +#define RES_IPV6ONLY 0x00000004 /*%< IPv6 only */ + +/*% + * Resolver options (keep these in synch with res_debug.c, please) + */ +#define RES_INIT 0x00000001 /*%< address initialized */ +#define RES_DEBUG 0x00000002 /*%< print debug messages */ +#define RES_AAONLY 0x00000004 /*%< authoritative answers only (!IMPL)*/ +#define RES_USEVC 0x00000008 /*%< use virtual circuit */ +#define RES_PRIMARY 0x00000010 /*%< query primary server only (!IMPL) */ +#define RES_IGNTC 0x00000020 /*%< ignore trucation errors */ +#define RES_RECURSE 0x00000040 /*%< recursion desired */ +#define RES_DEFNAMES 0x00000080 /*%< use default domain name */ +#define RES_STAYOPEN 0x00000100 /*%< Keep TCP socket open */ +#define RES_DNSRCH 0x00000200 /*%< search up local domain tree */ +#define RES_INSECURE1 0x00000400 /*%< type 1 security disabled */ +#define RES_INSECURE2 0x00000800 /*%< type 2 security disabled */ +#define RES_NOALIASES 0x00001000 /*%< shuts off HOSTALIASES feature */ +#define RES_USE_INET6 0x00002000 /*%< use/map IPv6 in gethostbyname() */ +#define RES_ROTATE 0x00004000 /*%< rotate ns list after each query */ +#define RES_NOCHECKNAME 0x00008000 /*%< do not check names for sanity. */ +#define RES_KEEPTSIG 0x00010000 /*%< do not strip TSIG records */ +#define RES_BLAST 0x00020000 /*%< blast all recursive servers */ +#define RES_NSID 0x00040000 /*%< request name server ID */ +#define RES_NOTLDQUERY 0x00100000 /*%< don't unqualified name as a tld */ +#define RES_USE_DNSSEC 0x00200000 /*%< use DNSSEC using OK bit in OPT */ +/* #define RES_DEBUG2 0x00400000 */ /* nslookup internal */ +/* KAME extensions: use higher bit to avoid conflict with ISC use */ +#define RES_USE_DNAME 0x10000000 /*%< use DNAME */ +#define RES_USE_EDNS0 0x40000000 /*%< use EDNS0 if configured */ +#define RES_NO_NIBBLE2 0x80000000 /*%< disable alternate nibble lookup */ + +#define RES_DEFAULT (RES_RECURSE | RES_DEFNAMES | \ + RES_DNSRCH | RES_NO_NIBBLE2) + +/*% + * Resolver "pfcode" values. Used by dig. + */ +#define RES_PRF_STATS 0x00000001 +#define RES_PRF_UPDATE 0x00000002 +#define RES_PRF_CLASS 0x00000004 +#define RES_PRF_CMD 0x00000008 +#define RES_PRF_QUES 0x00000010 +#define RES_PRF_ANS 0x00000020 +#define RES_PRF_AUTH 0x00000040 +#define RES_PRF_ADD 0x00000080 +#define RES_PRF_HEAD1 0x00000100 +#define RES_PRF_HEAD2 0x00000200 +#define RES_PRF_TTLID 0x00000400 +#define RES_PRF_HEADX 0x00000800 +#define RES_PRF_QUERY 0x00001000 +#define RES_PRF_REPLY 0x00002000 +#define RES_PRF_INIT 0x00004000 +#define RES_PRF_TRUNC 0x00008000 +/* 0x00010000 */ + +/* Things involving an internal (static) resolver context. */ +#ifdef _REENTRANT +__BEGIN_DECLS +extern struct __res_state *__res_state(void); +__END_DECLS +#define _res (*__res_state()) +#else +#ifdef __linux +__BEGIN_DECLS +extern struct __res_state * __res_state(void); +__END_DECLS +#endif +#ifndef __BIND_NOSTATIC +extern struct __res_state _res; +#endif +#endif + +#ifndef __BIND_NOSTATIC +#define fp_nquery __fp_nquery +#define fp_query __fp_query +#define hostalias __hostalias +#define p_query __p_query +#define res_close __res_close +#define res_init __res_init +#define res_isourserver __res_isourserver +#define res_mkquery __res_mkquery +#define res_query __res_query +#define res_querydomain __res_querydomain +#define res_search __res_search +#define res_send __res_send +#define res_sendsigned __res_sendsigned + +__BEGIN_DECLS +void fp_nquery __P((const u_char *, int, FILE *)); +void fp_query __P((const u_char *, FILE *)); +const char * hostalias __P((const char *)); +void p_query __P((const u_char *)); +void res_close __P((void)); +int res_init __P((void)); +int res_isourserver __P((const struct sockaddr_in *)); +int res_mkquery __P((int, const char *, int, int, const u_char *, + int, const u_char *, u_char *, int)); +int res_query __P((const char *, int, int, u_char *, int)); +int res_querydomain __P((const char *, const char *, int, int, + u_char *, int)); +int res_search __P((const char *, int, int, u_char *, int)); +int res_send __P((const u_char *, int, u_char *, int)); +int res_sendsigned __P((const u_char *, int, ns_tsig_key *, + u_char *, int)); +__END_DECLS +#endif + +#if !defined(SHARED_LIBBIND) || defined(LIB) +/* + * If libbind is a shared object (well, DLL anyway) + * these externs break the linker when resolv.h is + * included by a lib client (like named) + * Make them go away if a client is including this + * + */ +extern const struct res_sym __p_key_syms[]; +extern const struct res_sym __p_cert_syms[]; +extern const struct res_sym __p_class_syms[]; +extern const struct res_sym __p_type_syms[]; +extern const struct res_sym __p_rcode_syms[]; +#endif /* SHARED_LIBBIND */ + +#define b64_ntop __b64_ntop +#define b64_pton __b64_pton +#define dn_comp __dn_comp +#define dn_count_labels __dn_count_labels +#define dn_expand __dn_expand +#define dn_skipname __dn_skipname +#define fp_resstat __fp_resstat +#define loc_aton __loc_aton +#define loc_ntoa __loc_ntoa +#define p_cdname __p_cdname +#define p_cdnname __p_cdnname +#define p_class __p_class +#define p_fqname __p_fqname +#define p_fqnname __p_fqnname +#define p_option __p_option +#define p_secstodate __p_secstodate +#define p_section __p_section +#define p_time __p_time +#define p_type __p_type +#define p_rcode __p_rcode +#define p_sockun __p_sockun +#define putlong __putlong +#define putshort __putshort +#define res_dnok __res_dnok +#define res_findzonecut __res_findzonecut +#define res_findzonecut2 __res_findzonecut2 +#define res_hnok __res_hnok +#define res_hostalias __res_hostalias +#define res_mailok __res_mailok +#define res_nameinquery __res_nameinquery +#define res_nclose __res_nclose +#define res_ninit __res_ninit +#define res_nmkquery __res_nmkquery +#define res_pquery __res_pquery +#define res_nquery __res_nquery +#define res_nquerydomain __res_nquerydomain +#define res_nsearch __res_nsearch +#define res_nsend __res_nsend +#define res_nsendsigned __res_nsendsigned +#define res_nisourserver __res_nisourserver +#define res_ownok __res_ownok +#define res_queriesmatch __res_queriesmatch +#define res_randomid __res_randomid +#define sym_ntop __sym_ntop +#define sym_ntos __sym_ntos +#define sym_ston __sym_ston +#define res_nopt __res_nopt +#define res_nopt_rdata __res_nopt_rdata +#define res_ndestroy __res_ndestroy +#define res_nametoclass __res_nametoclass +#define res_nametotype __res_nametotype +#define res_setservers __res_setservers +#define res_getservers __res_getservers +#define res_buildprotolist __res_buildprotolist +#define res_destroyprotolist __res_destroyprotolist +#define res_destroyservicelist __res_destroyservicelist +#define res_get_nibblesuffix __res_get_nibblesuffix +#define res_get_nibblesuffix2 __res_get_nibblesuffix2 +#define res_ourserver_p __res_ourserver_p +#define res_protocolname __res_protocolname +#define res_protocolnumber __res_protocolnumber +#define res_send_setqhook __res_send_setqhook +#define res_send_setrhook __res_send_setrhook +#define res_servicename __res_servicename +#define res_servicenumber __res_servicenumber +__BEGIN_DECLS +int res_hnok __P((const char *)); +int res_ownok __P((const char *)); +int res_mailok __P((const char *)); +int res_dnok __P((const char *)); +int sym_ston __P((const struct res_sym *, const char *, int *)); +const char * sym_ntos __P((const struct res_sym *, int, int *)); +const char * sym_ntop __P((const struct res_sym *, int, int *)); +int b64_ntop __P((u_char const *, size_t, char *, size_t)); +int b64_pton __P((char const *, u_char *, size_t)); +int loc_aton __P((const char *, u_char *)); +const char * loc_ntoa __P((const u_char *, char *)); +int dn_skipname __P((const u_char *, const u_char *)); +void putlong __P((u_int32_t, u_char *)); +void putshort __P((u_int16_t, u_char *)); +#ifndef __ultrix__ +u_int16_t _getshort __P((const u_char *)); +u_int32_t _getlong __P((const u_char *)); +#endif +const char * p_class __P((int)); +const char * p_time __P((u_int32_t)); +const char * p_type __P((int)); +const char * p_rcode __P((int)); +const char * p_sockun __P((union res_sockaddr_union, char *, size_t)); +const u_char * p_cdnname __P((const u_char *, const u_char *, int, FILE *)); +const u_char * p_cdname __P((const u_char *, const u_char *, FILE *)); +const u_char * p_fqnname __P((const u_char *, const u_char *, + int, char *, int)); +const u_char * p_fqname __P((const u_char *, const u_char *, FILE *)); +const char * p_option __P((u_long)); +char * p_secstodate __P((u_long)); +int dn_count_labels __P((const char *)); +int dn_comp __P((const char *, u_char *, int, + u_char **, u_char **)); +int dn_expand __P((const u_char *, const u_char *, const u_char *, + char *, int)); +u_int res_randomid __P((void)); +int res_nameinquery __P((const char *, int, int, const u_char *, + const u_char *)); +int res_queriesmatch __P((const u_char *, const u_char *, + const u_char *, const u_char *)); +const char * p_section __P((int, int)); +/* Things involving a resolver context. */ +int res_ninit __P((res_state)); +int res_nisourserver __P((const res_state, + const struct sockaddr_in *)); +void fp_resstat __P((const res_state, FILE *)); +void res_pquery __P((const res_state, const u_char *, int, FILE *)); +const char * res_hostalias __P((const res_state, const char *, + char *, size_t)); +int res_nquery __P((res_state, const char *, int, int, + u_char *, int)); +int res_nsearch __P((res_state, const char *, int, int, u_char *, + int)); +int res_nquerydomain __P((res_state, const char *, const char *, + int, int, u_char *, int)); +int res_nmkquery __P((res_state, int, const char *, int, int, + const u_char *, int, const u_char *, + u_char *, int)); +int res_nsend __P((res_state, const u_char *, int, u_char *, int)); +int res_nsendsigned __P((res_state, const u_char *, int, + ns_tsig_key *, u_char *, int)); +int res_findzonecut __P((res_state, const char *, ns_class, int, + char *, size_t, struct in_addr *, int)); +int res_findzonecut2 __P((res_state, const char *, ns_class, int, + char *, size_t, + union res_sockaddr_union *, int)); +void res_nclose __P((res_state)); +int res_nopt __P((res_state, int, u_char *, int, int)); +int res_nopt_rdata __P((res_state, int, u_char *, int, u_char *, + u_short, u_short, u_char *)); +void res_send_setqhook __P((res_send_qhook)); +void res_send_setrhook __P((res_send_rhook)); +int __res_vinit __P((res_state, int)); +void res_destroyservicelist __P((void)); +const char * res_servicename __P((u_int16_t, const char *)); +const char * res_protocolname __P((int)); +void res_destroyprotolist __P((void)); +void res_buildprotolist __P((void)); +const char * res_get_nibblesuffix __P((res_state)); +const char * res_get_nibblesuffix2 __P((res_state)); +void res_ndestroy __P((res_state)); +u_int16_t res_nametoclass __P((const char *, int *)); +u_int16_t res_nametotype __P((const char *, int *)); +void res_setservers __P((res_state, + const union res_sockaddr_union *, int)); +int res_getservers __P((res_state, + union res_sockaddr_union *, int)); +__END_DECLS + +#endif /* !_RESOLV_H_ */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/include/resolv_mt.h b/contrib/bind-9.5.2/lib/bind/include/resolv_mt.h new file mode 100644 index 0000000000..27963a1207 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/include/resolv_mt.h @@ -0,0 +1,47 @@ +#ifndef _RESOLV_MT_H +#define _RESOLV_MT_H + +#include +#include +#include +#include + +/* Access functions for the libresolv private interface */ + +int __res_enable_mt(void); +int __res_disable_mt(void); + +/* Per-thread context */ + +typedef struct { +int no_hosts_fallback_private; +int retry_save; +int retry_private; +char inet_nsap_ntoa_tmpbuf[255*3]; +char sym_ntos_unname[20]; +char sym_ntop_unname[20]; +char p_option_nbuf[40]; +char p_time_nbuf[40]; +char precsize_ntoa_retbuf[sizeof "90000000.00"]; +char loc_ntoa_tmpbuf[sizeof +"1000 60 60.000 N 1000 60 60.000 W -12345678.00m 90000000.00m 90000000.00m 90000000.00m"]; +char p_secstodate_output[15]; +} mtctxres_t; + +/* Thread-specific data (TSD) */ + +mtctxres_t *___mtctxres(void); +#define mtctxres (___mtctxres()) + +/* Various static data that should be TSD */ + +#define sym_ntos_unname (mtctxres->sym_ntos_unname) +#define sym_ntop_unname (mtctxres->sym_ntop_unname) +#define inet_nsap_ntoa_tmpbuf (mtctxres->inet_nsap_ntoa_tmpbuf) +#define p_option_nbuf (mtctxres->p_option_nbuf) +#define p_time_nbuf (mtctxres->p_time_nbuf) +#define precsize_ntoa_retbuf (mtctxres->precsize_ntoa_retbuf) +#define loc_ntoa_tmpbuf (mtctxres->loc_ntoa_tmpbuf) +#define p_secstodate_output (mtctxres->p_secstodate_output) + +#endif /* _RESOLV_MT_H */ diff --git a/contrib/bind-9.5.2/lib/bind/inet/inet_addr.c b/contrib/bind-9.5.2/lib/bind/inet/inet_addr.c new file mode 100644 index 0000000000..56270ffa3a --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/inet/inet_addr.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 1983, 1990, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION 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. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93"; +static const char rcsid[] = "$Id: inet_addr.c,v 1.5 2005/04/27 04:56:19 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include "port_before.h" + +#include +#include + +#include +#include + +#include + +#include "port_after.h" + +/*% + * Ascii internet address interpretation routine. + * The value returned is in network order. + */ +u_long +inet_addr(const char *cp) { + struct in_addr val; + + if (inet_aton(cp, &val)) + return (val.s_addr); + return (INADDR_NONE); +} + +/*% + * Check whether "cp" is a valid ascii representation + * of an Internet address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * This replaces inet_addr, the return value from which + * cannot distinguish between failure and a local broadcast address. + */ +int +inet_aton(const char *cp, struct in_addr *addr) { + u_long val; + int base, n; + char c; + u_int8_t parts[4]; + u_int8_t *pp = parts; + int digit; + + c = *cp; + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, isdigit=decimal. + */ + if (!isdigit((unsigned char)c)) + return (0); + val = 0; base = 10; digit = 0; + if (c == '0') { + c = *++cp; + if (c == 'x' || c == 'X') + base = 16, c = *++cp; + else { + base = 8; + digit = 1 ; + } + } + for (;;) { + if (isascii(c) && isdigit((unsigned char)c)) { + if (base == 8 && (c == '8' || c == '9')) + return (0); + val = (val * base) + (c - '0'); + c = *++cp; + digit = 1; + } else if (base == 16 && isascii(c) && + isxdigit((unsigned char)c)) { + val = (val << 4) | + (c + 10 - (islower((unsigned char)c) ? 'a' : 'A')); + c = *++cp; + digit = 1; + } else + break; + } + if (c == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16 bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3 || val > 0xffU) + return (0); + *pp++ = val; + c = *++cp; + } else + break; + } + /* + * Check for trailing characters. + */ + if (c != '\0' && (!isascii(c) || !isspace((unsigned char)c))) + return (0); + /* + * Did we get a valid digit? + */ + if (!digit) + return (0); + /* + * Concoct the address according to + * the number of parts specified. + */ + n = pp - parts + 1; + switch (n) { + case 1: /*%< a -- 32 bits */ + break; + + case 2: /*%< a.b -- 8.24 bits */ + if (val > 0xffffffU) + return (0); + val |= parts[0] << 24; + break; + + case 3: /*%< a.b.c -- 8.8.16 bits */ + if (val > 0xffffU) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /*%< a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xffU) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + } + if (addr != NULL) + addr->s_addr = htonl(val); + return (1); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/inet/inet_cidr_ntop.c b/contrib/bind-9.5.2/lib/bind/inet/inet_cidr_ntop.c new file mode 100644 index 0000000000..bf960a8acc --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/inet/inet_cidr_ntop.c @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1998,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: inet_cidr_ntop.c,v 1.7 2006/10/11 02:18:18 marka Exp $"; +#endif + +#include "port_before.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "port_after.h" + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +static char * +inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size); +static char * +inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size); + +/*% + * char * + * inet_cidr_ntop(af, src, bits, dst, size) + * convert network address from network to presentation format. + * "src"'s size is determined from its "af". + * return: + * pointer to dst, or NULL if an error occurred (check errno). + * note: + * 192.5.5.1/28 has a nonzero host part, which means it isn't a network + * as called for by inet_net_ntop() but it can be a host address with + * an included netmask. + * author: + * Paul Vixie (ISC), October 1998 + */ +char * +inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size) { + switch (af) { + case AF_INET: + return (inet_cidr_ntop_ipv4(src, bits, dst, size)); + case AF_INET6: + return (inet_cidr_ntop_ipv6(src, bits, dst, size)); + default: + errno = EAFNOSUPPORT; + return (NULL); + } +} + +static int +decoct(const u_char *src, int bytes, char *dst, size_t size) { + char *odst = dst; + char *t; + int b; + + for (b = 1; b <= bytes; b++) { + if (size < sizeof "255.") + return (0); + t = dst; + dst += SPRINTF((dst, "%u", *src++)); + if (b != bytes) { + *dst++ = '.'; + *dst = '\0'; + } + size -= (size_t)(dst - t); + } + return (dst - odst); +} + +/*% + * static char * + * inet_cidr_ntop_ipv4(src, bits, dst, size) + * convert IPv4 network address from network to presentation format. + * "src"'s size is determined from its "af". + * return: + * pointer to dst, or NULL if an error occurred (check errno). + * note: + * network byte order assumed. this means 192.5.5.240/28 has + * 0b11110000 in its fourth octet. + * author: + * Paul Vixie (ISC), October 1998 + */ +static char * +inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) { + char *odst = dst; + size_t len = 4; + size_t b; + size_t bytes; + + if ((bits < -1) || (bits > 32)) { + errno = EINVAL; + return (NULL); + } + + /* Find number of significant bytes in address. */ + if (bits == -1) + len = 4; + else + for (len = 1, b = 1 ; b < 4U; b++) + if (*(src + b)) + len = b + 1; + + /* Format whole octets plus nonzero trailing octets. */ + bytes = (((bits <= 0) ? 1 : bits) + 7) / 8; + if (len > bytes) + bytes = len; + b = decoct(src, bytes, dst, size); + if (b == 0U) + goto emsgsize; + dst += b; + size -= b; + + if (bits != -1) { + /* Format CIDR /width. */ + if (size < sizeof "/32") + goto emsgsize; + dst += SPRINTF((dst, "/%u", bits)); + } + + return (odst); + + emsgsize: + errno = EMSGSIZE; + return (NULL); +} + +static char * +inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) { + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"]; + char *tp; + struct { int base, len; } best, cur; + u_int words[NS_IN6ADDRSZ / NS_INT16SZ]; + int i; + + if ((bits < -1) || (bits > 128)) { + errno = EINVAL; + return (NULL); + } + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof words); + for (i = 0; i < NS_IN6ADDRSZ; i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + best.len = 0; + cur.base = -1; + cur.len = 0; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + if (words[i] == 0) { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) { + if (i == best.base) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && (best.len == 6 || + (best.len == 7 && words[7] != 0x0001) || + (best.len == 5 && words[5] == 0xffff))) { + int n; + + if (src[15] || bits == -1 || bits > 120) + n = 4; + else if (src[14] || bits > 112) + n = 3; + else + n = 2; + n = decoct(src+12, n, tp, sizeof tmp - (tp - tmp)); + if (n == 0) { + errno = EMSGSIZE; + return (NULL); + } + tp += strlen(tp); + break; + } + tp += SPRINTF((tp, "%x", words[i])); + } + + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == + (NS_IN6ADDRSZ / NS_INT16SZ)) + *tp++ = ':'; + *tp = '\0'; + + if (bits != -1) + tp += SPRINTF((tp, "/%u", bits)); + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t)(tp - tmp) > size) { + errno = EMSGSIZE; + return (NULL); + } + strcpy(dst, tmp); + return (dst); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/inet/inet_cidr_pton.c b/contrib/bind-9.5.2/lib/bind/inet/inet_cidr_pton.c new file mode 100644 index 0000000000..07652af463 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/inet/inet_cidr_pton.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1998,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: inet_cidr_pton.c,v 1.6 2005/04/27 04:56:19 sra Exp $"; +#endif + +#include "port_before.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "port_after.h" + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +static int inet_cidr_pton_ipv4 __P((const char *src, u_char *dst, + int *bits, int ipv6)); +static int inet_cidr_pton_ipv6 __P((const char *src, u_char *dst, + int *bits)); + +static int getbits(const char *, int ipv6); + +/*% + * int + * inet_cidr_pton(af, src, dst, *bits) + * convert network address from presentation to network format. + * accepts inet_pton()'s input for this "af" plus trailing "/CIDR". + * "dst" is assumed large enough for its "af". "bits" is set to the + * /CIDR prefix length, which can have defaults (like /32 for IPv4). + * return: + * -1 if an error occurred (inspect errno; ENOENT means bad format). + * 0 if successful conversion occurred. + * note: + * 192.5.5.1/28 has a nonzero host part, which means it isn't a network + * as called for by inet_net_pton() but it can be a host address with + * an included netmask. + * author: + * Paul Vixie (ISC), October 1998 + */ +int +inet_cidr_pton(int af, const char *src, void *dst, int *bits) { + switch (af) { + case AF_INET: + return (inet_cidr_pton_ipv4(src, dst, bits, 0)); + case AF_INET6: + return (inet_cidr_pton_ipv6(src, dst, bits)); + default: + errno = EAFNOSUPPORT; + return (-1); + } +} + +static const char digits[] = "0123456789"; + +static int +inet_cidr_pton_ipv4(const char *src, u_char *dst, int *pbits, int ipv6) { + const u_char *odst = dst; + int n, ch, tmp, bits; + size_t size = 4; + + /* Get the mantissa. */ + while (ch = *src++, (isascii(ch) && isdigit(ch))) { + tmp = 0; + do { + n = strchr(digits, ch) - digits; + INSIST(n >= 0 && n <= 9); + tmp *= 10; + tmp += n; + if (tmp > 255) + goto enoent; + } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch)); + if (size-- == 0U) + goto emsgsize; + *dst++ = (u_char) tmp; + if (ch == '\0' || ch == '/') + break; + if (ch != '.') + goto enoent; + } + + /* Get the prefix length if any. */ + bits = -1; + if (ch == '/' && dst > odst) { + bits = getbits(src, ipv6); + if (bits == -2) + goto enoent; + } else if (ch != '\0') + goto enoent; + + /* Prefix length can default to /32 only if all four octets spec'd. */ + if (bits == -1) { + if (dst - odst == 4) + bits = ipv6 ? 128 : 32; + else + goto enoent; + } + + /* If nothing was written to the destination, we found no address. */ + if (dst == odst) + goto enoent; + + /* If prefix length overspecifies mantissa, life is bad. */ + if (((bits - (ipv6 ? 96 : 0)) / 8) > (dst - odst)) + goto enoent; + + /* Extend address to four octets. */ + while (size-- > 0U) + *dst++ = 0; + + *pbits = bits; + return (0); + + enoent: + errno = ENOENT; + return (-1); + + emsgsize: + errno = EMSGSIZE; + return (-1); +} + +static int +inet_cidr_pton_ipv6(const char *src, u_char *dst, int *pbits) { + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + u_int val; + int bits; + + memset((tp = tmp), '\0', NS_IN6ADDRSZ); + endp = tp + NS_IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return (0); + curtok = src; + saw_xdigit = 0; + val = 0; + bits = -1; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (val > 0xffff) + return (0); + saw_xdigit = 1; + continue; + } + if (ch == ':') { + curtok = src; + if (!saw_xdigit) { + if (colonp) + return (0); + colonp = tp; + continue; + } else if (*src == '\0') { + return (0); + } + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + inet_cidr_pton_ipv4(curtok, tp, &bits, 1) == 0) { + tp += NS_INADDRSZ; + saw_xdigit = 0; + break; /*%< '\\0' was seen by inet_pton4(). */ + } + if (ch == '/') { + bits = getbits(src, 1); + if (bits == -2) + goto enoent; + break; + } + goto enoent; + } + if (saw_xdigit) { + if (tp + NS_INT16SZ > endp) + goto emsgsize; + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + } + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + if (tp == endp) + goto enoent; + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + + memcpy(dst, tmp, NS_IN6ADDRSZ); + + *pbits = bits; + return (0); + + enoent: + errno = ENOENT; + return (-1); + + emsgsize: + errno = EMSGSIZE; + return (-1); +} + +static int +getbits(const char *src, int ipv6) { + int bits = 0; + char *cp, ch; + + if (*src == '\0') /*%< syntax */ + return (-2); + do { + ch = *src++; + cp = strchr(digits, ch); + if (cp == NULL) /*%< syntax */ + return (-2); + bits *= 10; + bits += cp - digits; + if (bits == 0 && *src != '\0') /*%< no leading zeros */ + return (-2); + if (bits > (ipv6 ? 128 : 32)) /*%< range error */ + return (-2); + } while (*src != '\0'); + + return (bits); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/inet/inet_data.c b/contrib/bind-9.5.2/lib/bind/inet/inet_data.c new file mode 100644 index 0000000000..4373a171a0 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/inet/inet_data.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1995-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = "$Id: inet_data.c,v 1.4 2005/04/27 04:56:19 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include "port_before.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "port_after.h" + +const struct in6_addr isc_in6addr_any = IN6ADDR_ANY_INIT; +const struct in6_addr isc_in6addr_loopback = IN6ADDR_LOOPBACK_INIT; + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/inet/inet_lnaof.c b/contrib/bind-9.5.2/lib/bind/inet/inet_lnaof.c new file mode 100644 index 0000000000..70ac409512 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/inet/inet_lnaof.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)inet_lnaof.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include "port_before.h" + +#include +#include +#include + +#include "port_after.h" + +/*% + * Return the local network address portion of an + * internet address; handles class a/b/c network + * number formats. + */ +u_long +inet_lnaof(in) + struct in_addr in; +{ + register u_long i = ntohl(in.s_addr); + + if (IN_CLASSA(i)) + return ((i)&IN_CLASSA_HOST); + else if (IN_CLASSB(i)) + return ((i)&IN_CLASSB_HOST); + else + return ((i)&IN_CLASSC_HOST); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/inet/inet_makeaddr.c b/contrib/bind-9.5.2/lib/bind/inet/inet_makeaddr.c new file mode 100644 index 0000000000..c56cb3eaeb --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/inet/inet_makeaddr.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)inet_makeaddr.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include "port_before.h" + +#include +#include +#include + +#include "port_after.h" + +/*% + * Formulate an Internet address from network + host. Used in + * building addresses stored in the ifnet structure. + */ +struct in_addr +inet_makeaddr(net, host) + u_long net, host; +{ + struct in_addr a; + + if (net < 128U) + a.s_addr = (net << IN_CLASSA_NSHIFT) | (host & IN_CLASSA_HOST); + else if (net < 65536U) + a.s_addr = (net << IN_CLASSB_NSHIFT) | (host & IN_CLASSB_HOST); + else if (net < 16777216L) + a.s_addr = (net << IN_CLASSC_NSHIFT) | (host & IN_CLASSC_HOST); + else + a.s_addr = net | host; + a.s_addr = htonl(a.s_addr); + return (a); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/inet/inet_net_ntop.c b/contrib/bind-9.5.2/lib/bind/inet/inet_net_ntop.c new file mode 100644 index 0000000000..fb28e3cbe5 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/inet/inet_net_ntop.c @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.5 2006/06/20 02:50:14 marka Exp $"; +#endif + +#include "port_before.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "port_after.h" + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +static char * inet_net_ntop_ipv4 __P((const u_char *src, int bits, + char *dst, size_t size)); +static char * inet_net_ntop_ipv6 __P((const u_char *src, int bits, + char *dst, size_t size)); + +/*% + * char * + * inet_net_ntop(af, src, bits, dst, size) + * convert network number from network to presentation format. + * generates CIDR style result always. + * return: + * pointer to dst, or NULL if an error occurred (check errno). + * author: + * Paul Vixie (ISC), July 1996 + */ +char * +inet_net_ntop(af, src, bits, dst, size) + int af; + const void *src; + int bits; + char *dst; + size_t size; +{ + switch (af) { + case AF_INET: + return (inet_net_ntop_ipv4(src, bits, dst, size)); + case AF_INET6: + return (inet_net_ntop_ipv6(src, bits, dst, size)); + default: + errno = EAFNOSUPPORT; + return (NULL); + } +} + +/*% + * static char * + * inet_net_ntop_ipv4(src, bits, dst, size) + * convert IPv4 network number from network to presentation format. + * generates CIDR style result always. + * return: + * pointer to dst, or NULL if an error occurred (check errno). + * note: + * network byte order assumed. this means 192.5.5.240/28 has + * 0b11110000 in its fourth octet. + * author: + * Paul Vixie (ISC), July 1996 + */ +static char * +inet_net_ntop_ipv4(src, bits, dst, size) + const u_char *src; + int bits; + char *dst; + size_t size; +{ + char *odst = dst; + char *t; + u_int m; + int b; + + if (bits < 0 || bits > 32) { + errno = EINVAL; + return (NULL); + } + + if (bits == 0) { + if (size < sizeof "0") + goto emsgsize; + *dst++ = '0'; + size--; + *dst = '\0'; + } + + /* Format whole octets. */ + for (b = bits / 8; b > 0; b--) { + if (size <= sizeof "255.") + goto emsgsize; + t = dst; + dst += SPRINTF((dst, "%u", *src++)); + if (b > 1) { + *dst++ = '.'; + *dst = '\0'; + } + size -= (size_t)(dst - t); + } + + /* Format partial octet. */ + b = bits % 8; + if (b > 0) { + if (size <= sizeof ".255") + goto emsgsize; + t = dst; + if (dst != odst) + *dst++ = '.'; + m = ((1 << b) - 1) << (8 - b); + dst += SPRINTF((dst, "%u", *src & m)); + size -= (size_t)(dst - t); + } + + /* Format CIDR /width. */ + if (size <= sizeof "/32") + goto emsgsize; + dst += SPRINTF((dst, "/%u", bits)); + return (odst); + + emsgsize: + errno = EMSGSIZE; + return (NULL); +} + +/*% + * static char * + * inet_net_ntop_ipv6(src, bits, fakebits, dst, size) + * convert IPv6 network number from network to presentation format. + * generates CIDR style result always. Picks the shortest representation + * unless the IP is really IPv4. + * always prints specified number of bits (bits). + * return: + * pointer to dst, or NULL if an error occurred (check errno). + * note: + * network byte order assumed. this means 192.5.5.240/28 has + * 0x11110000 in its fourth octet. + * author: + * Vadim Kogan (UCB), June 2001 + * Original version (IPv4) by Paul Vixie (ISC), July 1996 + */ + +static char * +inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) { + u_int m; + int b; + int p; + int zero_s, zero_l, tmp_zero_s, tmp_zero_l; + int i; + int is_ipv4 = 0; + unsigned char inbuf[16]; + char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")]; + char *cp; + int words; + u_char *s; + + if (bits < 0 || bits > 128) { + errno = EINVAL; + return (NULL); + } + + cp = outbuf; + + if (bits == 0) { + *cp++ = ':'; + *cp++ = ':'; + *cp = '\0'; + } else { + /* Copy src to private buffer. Zero host part. */ + p = (bits + 7) / 8; + memcpy(inbuf, src, p); + memset(inbuf + p, 0, 16 - p); + b = bits % 8; + if (b != 0) { + m = ~0 << (8 - b); + inbuf[p-1] &= m; + } + + s = inbuf; + + /* how many words need to be displayed in output */ + words = (bits + 15) / 16; + if (words == 1) + words = 2; + + /* Find the longest substring of zero's */ + zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0; + for (i = 0; i < (words * 2); i += 2) { + if ((s[i] | s[i+1]) == 0) { + if (tmp_zero_l == 0) + tmp_zero_s = i / 2; + tmp_zero_l++; + } else { + if (tmp_zero_l && zero_l < tmp_zero_l) { + zero_s = tmp_zero_s; + zero_l = tmp_zero_l; + tmp_zero_l = 0; + } + } + } + + if (tmp_zero_l && zero_l < tmp_zero_l) { + zero_s = tmp_zero_s; + zero_l = tmp_zero_l; + } + + if (zero_l != words && zero_s == 0 && ((zero_l == 6) || + ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) || + ((zero_l == 7 && s[14] != 0 && s[15] != 1))))) + is_ipv4 = 1; + + /* Format whole words. */ + for (p = 0; p < words; p++) { + if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) { + /* Time to skip some zeros */ + if (p == zero_s) + *cp++ = ':'; + if (p == words - 1) + *cp++ = ':'; + s++; + s++; + continue; + } + + if (is_ipv4 && p > 5 ) { + *cp++ = (p == 6) ? ':' : '.'; + cp += SPRINTF((cp, "%u", *s++)); + /* we can potentially drop the last octet */ + if (p != 7 || bits > 120) { + *cp++ = '.'; + cp += SPRINTF((cp, "%u", *s++)); + } + } else { + if (cp != outbuf) + *cp++ = ':'; + cp += SPRINTF((cp, "%x", *s * 256 + s[1])); + s += 2; + } + } + } + /* Format CIDR /width. */ + sprintf(cp, "/%u", bits); + if (strlen(outbuf) + 1 > size) + goto emsgsize; + strcpy(dst, outbuf); + + return (dst); + +emsgsize: + errno = EMSGSIZE; + return (NULL); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/inet/inet_net_pton.c b/contrib/bind-9.5.2/lib/bind/inet/inet_net_pton.c new file mode 100644 index 0000000000..b0ee27a45e --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/inet/inet_net_pton.c @@ -0,0 +1,407 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: inet_net_pton.c,v 1.8.672.1 2008/08/26 04:42:38 marka Exp $"; +#endif + +#include "port_before.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "port_after.h" + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +/*% + * static int + * inet_net_pton_ipv4(src, dst, size) + * convert IPv4 network number from presentation to network format. + * accepts hex octets, hex strings, decimal octets, and /CIDR. + * "size" is in bytes and describes "dst". + * return: + * number of bits, either imputed classfully or specified with /CIDR, + * or -1 if some failure occurred (check errno). ENOENT means it was + * not an IPv4 network specification. + * note: + * network byte order assumed. this means 192.5.5.240/28 has + * 0b11110000 in its fourth octet. + * author: + * Paul Vixie (ISC), June 1996 + */ +static int +inet_net_pton_ipv4(const char *src, u_char *dst, size_t size) { + static const char xdigits[] = "0123456789abcdef"; + static const char digits[] = "0123456789"; + int n, ch, tmp = 0, dirty, bits; + const u_char *odst = dst; + + ch = *src++; + if (ch == '0' && (src[0] == 'x' || src[0] == 'X') + && isascii((unsigned char)(src[1])) + && isxdigit((unsigned char)(src[1]))) { + /* Hexadecimal: Eat nybble string. */ + if (size <= 0U) + goto emsgsize; + dirty = 0; + src++; /*%< skip x or X. */ + while ((ch = *src++) != '\0' && isascii(ch) && isxdigit(ch)) { + if (isupper(ch)) + ch = tolower(ch); + n = strchr(xdigits, ch) - xdigits; + INSIST(n >= 0 && n <= 15); + if (dirty == 0) + tmp = n; + else + tmp = (tmp << 4) | n; + if (++dirty == 2) { + if (size-- <= 0U) + goto emsgsize; + *dst++ = (u_char) tmp; + dirty = 0; + } + } + if (dirty) { /*%< Odd trailing nybble? */ + if (size-- <= 0U) + goto emsgsize; + *dst++ = (u_char) (tmp << 4); + } + } else if (isascii(ch) && isdigit(ch)) { + /* Decimal: eat dotted digit string. */ + for (;;) { + tmp = 0; + do { + n = strchr(digits, ch) - digits; + INSIST(n >= 0 && n <= 9); + tmp *= 10; + tmp += n; + if (tmp > 255) + goto enoent; + } while ((ch = *src++) != '\0' && + isascii(ch) && isdigit(ch)); + if (size-- <= 0U) + goto emsgsize; + *dst++ = (u_char) tmp; + if (ch == '\0' || ch == '/') + break; + if (ch != '.') + goto enoent; + ch = *src++; + if (!isascii(ch) || !isdigit(ch)) + goto enoent; + } + } else + goto enoent; + + bits = -1; + if (ch == '/' && isascii((unsigned char)(src[0])) && + isdigit((unsigned char)(src[0])) && dst > odst) { + /* CIDR width specifier. Nothing can follow it. */ + ch = *src++; /*%< Skip over the /. */ + bits = 0; + do { + n = strchr(digits, ch) - digits; + INSIST(n >= 0 && n <= 9); + bits *= 10; + bits += n; + if (bits > 32) + goto enoent; + } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch)); + if (ch != '\0') + goto enoent; + } + + /* Firey death and destruction unless we prefetched EOS. */ + if (ch != '\0') + goto enoent; + + /* If nothing was written to the destination, we found no address. */ + if (dst == odst) + goto enoent; + /* If no CIDR spec was given, infer width from net class. */ + if (bits == -1) { + if (*odst >= 240) /*%< Class E */ + bits = 32; + else if (*odst >= 224) /*%< Class D */ + bits = 8; + else if (*odst >= 192) /*%< Class C */ + bits = 24; + else if (*odst >= 128) /*%< Class B */ + bits = 16; + else /*%< Class A */ + bits = 8; + /* If imputed mask is narrower than specified octets, widen. */ + if (bits < ((dst - odst) * 8)) + bits = (dst - odst) * 8; + /* + * If there are no additional bits specified for a class D + * address adjust bits to 4. + */ + if (bits == 8 && *odst == 224) + bits = 4; + } + /* Extend network to cover the actual mask. */ + while (bits > ((dst - odst) * 8)) { + if (size-- <= 0U) + goto emsgsize; + *dst++ = '\0'; + } + return (bits); + + enoent: + errno = ENOENT; + return (-1); + + emsgsize: + errno = EMSGSIZE; + return (-1); +} + +static int +getbits(const char *src, int *bitsp) { + static const char digits[] = "0123456789"; + int n; + int val; + char ch; + + val = 0; + n = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + pch = strchr(digits, ch); + if (pch != NULL) { + if (n++ != 0 && val == 0) /*%< no leading zeros */ + return (0); + val *= 10; + val += (pch - digits); + if (val > 128) /*%< range */ + return (0); + continue; + } + return (0); + } + if (n == 0) + return (0); + *bitsp = val; + return (1); +} + +static int +getv4(const char *src, u_char *dst, int *bitsp) { + static const char digits[] = "0123456789"; + u_char *odst = dst; + int n; + u_int val; + char ch; + + val = 0; + n = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + pch = strchr(digits, ch); + if (pch != NULL) { + if (n++ != 0 && val == 0) /*%< no leading zeros */ + return (0); + val *= 10; + val += (pch - digits); + if (val > 255) /*%< range */ + return (0); + continue; + } + if (ch == '.' || ch == '/') { + if (dst - odst > 3) /*%< too many octets? */ + return (0); + *dst++ = val; + if (ch == '/') + return (getbits(src, bitsp)); + val = 0; + n = 0; + continue; + } + return (0); + } + if (n == 0) + return (0); + if (dst - odst > 3) /*%< too many octets? */ + return (0); + *dst++ = val; + return (1); +} + +static int +inet_net_pton_ipv6(const char *src, u_char *dst, size_t size) { + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + u_int val; + int digits; + int bits; + size_t bytes; + int words; + int ipv4; + + memset((tp = tmp), '\0', NS_IN6ADDRSZ); + endp = tp + NS_IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + goto enoent; + curtok = src; + saw_xdigit = 0; + val = 0; + digits = 0; + bits = -1; + ipv4 = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (++digits > 4) + goto enoent; + saw_xdigit = 1; + continue; + } + if (ch == ':') { + curtok = src; + if (!saw_xdigit) { + if (colonp) + goto enoent; + colonp = tp; + continue; + } else if (*src == '\0') + goto enoent; + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + saw_xdigit = 0; + digits = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + getv4(curtok, tp, &bits) > 0) { + tp += NS_INADDRSZ; + saw_xdigit = 0; + ipv4 = 1; + break; /*%< '\\0' was seen by inet_pton4(). */ + } + if (ch == '/' && getbits(src, &bits) > 0) + break; + goto enoent; + } + if (saw_xdigit) { + if (tp + NS_INT16SZ > endp) + goto enoent; + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + } + if (bits == -1) + bits = 128; + + words = (bits + 15) / 16; + if (words < 2) + words = 2; + if (ipv4) + words = 8; + endp = tmp + 2 * words; + + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + if (tp == endp) + goto enoent; + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + goto enoent; + + bytes = (bits + 7) / 8; + if (bytes > size) + goto emsgsize; + memcpy(dst, tmp, bytes); + return (bits); + + enoent: + errno = ENOENT; + return (-1); + + emsgsize: + errno = EMSGSIZE; + return (-1); +} + +/*% + * int + * inet_net_pton(af, src, dst, size) + * convert network number from presentation to network format. + * accepts hex octets, hex strings, decimal octets, and /CIDR. + * "size" is in bytes and describes "dst". + * return: + * number of bits, either imputed classfully or specified with /CIDR, + * or -1 if some failure occurred (check errno). ENOENT means it was + * not a valid network specification. + * author: + * Paul Vixie (ISC), June 1996 + */ +int +inet_net_pton(int af, const char *src, void *dst, size_t size) { + switch (af) { + case AF_INET: + return (inet_net_pton_ipv4(src, dst, size)); + case AF_INET6: + return (inet_net_pton_ipv6(src, dst, size)); + default: + errno = EAFNOSUPPORT; + return (-1); + } +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/inet/inet_neta.c b/contrib/bind-9.5.2/lib/bind/inet/inet_neta.c new file mode 100644 index 0000000000..63a6c201a4 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/inet/inet_neta.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: inet_neta.c,v 1.3 2005/04/27 04:56:20 sra Exp $"; +#endif + +#include "port_before.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include "port_after.h" + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +/*% + * char * + * inet_neta(src, dst, size) + * format a u_long network number into presentation format. + * return: + * pointer to dst, or NULL if an error occurred (check errno). + * note: + * format of ``src'' is as for inet_network(). + * author: + * Paul Vixie (ISC), July 1996 + */ +char * +inet_neta(src, dst, size) + u_long src; + char *dst; + size_t size; +{ + char *odst = dst; + char *tp; + + while (src & 0xffffffff) { + u_char b = (src & 0xff000000) >> 24; + + src <<= 8; + if (b) { + if (size < sizeof "255.") + goto emsgsize; + tp = dst; + dst += SPRINTF((dst, "%u", b)); + if (src != 0L) { + *dst++ = '.'; + *dst = '\0'; + } + size -= (size_t)(dst - tp); + } + } + if (dst == odst) { + if (size < sizeof "0.0.0.0") + goto emsgsize; + strcpy(dst, "0.0.0.0"); + } + return (odst); + + emsgsize: + errno = EMSGSIZE; + return (NULL); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/inet/inet_netof.c b/contrib/bind-9.5.2/lib/bind/inet/inet_netof.c new file mode 100644 index 0000000000..c228e3d818 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/inet/inet_netof.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)inet_netof.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include "port_before.h" + +#include +#include +#include + +#include "port_after.h" + +/*% + * Return the network number from an internet + * address; handles class a/b/c network #'s. + */ +u_long +inet_netof(in) + struct in_addr in; +{ + register u_long i = ntohl(in.s_addr); + + if (IN_CLASSA(i)) + return (((i)&IN_CLASSA_NET) >> IN_CLASSA_NSHIFT); + else if (IN_CLASSB(i)) + return (((i)&IN_CLASSB_NET) >> IN_CLASSB_NSHIFT); + else + return (((i)&IN_CLASSC_NET) >> IN_CLASSC_NSHIFT); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/inet/inet_network.c b/contrib/bind-9.5.2/lib/bind/inet/inet_network.c new file mode 100644 index 0000000000..47976cff68 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/inet/inet_network.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)inet_network.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include "port_before.h" + +#include +#include +#include +#include + +#include "port_after.h" + +/*% + * Internet network address interpretation routine. + * The library routines call this routine to interpret + * network numbers. + */ +u_long +inet_network(cp) + register const char *cp; +{ + register u_long val, base, n, i; + register char c; + u_long parts[4], *pp = parts; + int digit; + +again: + val = 0; base = 10; digit = 0; + if (*cp == '0') + digit = 1, base = 8, cp++; + if (*cp == 'x' || *cp == 'X') + base = 16, cp++; + while ((c = *cp) != 0) { + if (isdigit((unsigned char)c)) { + if (base == 8U && (c == '8' || c == '9')) + return (INADDR_NONE); + val = (val * base) + (c - '0'); + cp++; + digit = 1; + continue; + } + if (base == 16U && isxdigit((unsigned char)c)) { + val = (val << 4) + + (c + 10 - (islower((unsigned char)c) ? 'a' : 'A')); + cp++; + digit = 1; + continue; + } + break; + } + if (!digit) + return (INADDR_NONE); + if (pp >= parts + 4 || val > 0xffU) + return (INADDR_NONE); + if (*cp == '.') { + *pp++ = val, cp++; + goto again; + } + if (*cp && !isspace(*cp&0xff)) + return (INADDR_NONE); + *pp++ = val; + n = pp - parts; + if (n > 4U) + return (INADDR_NONE); + for (val = 0, i = 0; i < n; i++) { + val <<= 8; + val |= parts[i] & 0xff; + } + return (val); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/inet/inet_ntoa.c b/contrib/bind-9.5.2/lib/bind/inet/inet_ntoa.c new file mode 100644 index 0000000000..983121e89d --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/inet/inet_ntoa.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)inet_ntoa.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: inet_ntoa.c,v 1.2 2005/04/27 04:56:21 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include "port_before.h" + +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +/*% + * Convert network-format internet address + * to base 256 d.d.d.d representation. + */ +/*const*/ char * +inet_ntoa(struct in_addr in) { + static char ret[18]; + + strcpy(ret, "[inet_ntoa error]"); + (void) inet_ntop(AF_INET, &in, ret, sizeof ret); + return (ret); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/inet/inet_ntop.c b/contrib/bind-9.5.2/lib/bind/inet/inet_ntop.c new file mode 100644 index 0000000000..114ca5d506 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/inet/inet_ntop.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: inet_ntop.c,v 1.5 2005/11/03 22:59:52 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include "port_before.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "port_after.h" + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +/*% + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static const char *inet_ntop4 __P((const u_char *src, char *dst, size_t size)); +static const char *inet_ntop6 __P((const u_char *src, char *dst, size_t size)); + +/* char * + * inet_ntop(af, src, dst, size) + * convert a network format address to presentation format. + * return: + * pointer to presentation format address (`dst'), or NULL (see errno). + * author: + * Paul Vixie, 1996. + */ +const char * +inet_ntop(af, src, dst, size) + int af; + const void *src; + char *dst; + size_t size; +{ + switch (af) { + case AF_INET: + return (inet_ntop4(src, dst, size)); + case AF_INET6: + return (inet_ntop6(src, dst, size)); + default: + errno = EAFNOSUPPORT; + return (NULL); + } + /* NOTREACHED */ +} + +/* const char * + * inet_ntop4(src, dst, size) + * format an IPv4 address + * return: + * `dst' (as a const) + * notes: + * (1) uses no statics + * (2) takes a u_char* not an in_addr as input + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop4(src, dst, size) + const u_char *src; + char *dst; + size_t size; +{ + static const char fmt[] = "%u.%u.%u.%u"; + char tmp[sizeof "255.255.255.255"]; + + if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) >= size) { + errno = ENOSPC; + return (NULL); + } + strcpy(dst, tmp); + return (dst); +} + +/* const char * + * inet_ntop6(src, dst, size) + * convert IPv6 binary address into presentation (printable) format + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop6(src, dst, size) + const u_char *src; + char *dst; + size_t size; +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; + struct { int base, len; } best, cur; + u_int words[NS_IN6ADDRSZ / NS_INT16SZ]; + int i; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof words); + for (i = 0; i < NS_IN6ADDRSZ; i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + best.len = 0; + cur.base = -1; + cur.len = 0; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + if (words[i] == 0) { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) { + if (i == best.base) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && (best.len == 6 || + (best.len == 7 && words[7] != 0x0001) || + (best.len == 5 && words[5] == 0xffff))) { + if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) + return (NULL); + tp += strlen(tp); + break; + } + tp += SPRINTF((tp, "%x", words[i])); + } + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == + (NS_IN6ADDRSZ / NS_INT16SZ)) + *tp++ = ':'; + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t)(tp - tmp) > size) { + errno = ENOSPC; + return (NULL); + } + strcpy(dst, tmp); + return (dst); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/inet/inet_pton.c b/contrib/bind-9.5.2/lib/bind/inet/inet_pton.c new file mode 100644 index 0000000000..2c516c798a --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/inet/inet_pton.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: inet_pton.c,v 1.5 2005/07/28 06:51:47 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include "port_before.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "port_after.h" + +/*% + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static int inet_pton4 __P((const char *src, u_char *dst)); +static int inet_pton6 __P((const char *src, u_char *dst)); + +/* int + * inet_pton(af, src, dst) + * convert from presentation format (which usually means ASCII printable) + * to network format (which is usually some kind of binary format). + * return: + * 1 if the address was valid for the specified address family + * 0 if the address wasn't valid (`dst' is untouched in this case) + * -1 if some other error occurred (`dst' is untouched in this case, too) + * author: + * Paul Vixie, 1996. + */ +int +inet_pton(af, src, dst) + int af; + const char *src; + void *dst; +{ + switch (af) { + case AF_INET: + return (inet_pton4(src, dst)); + case AF_INET6: + return (inet_pton6(src, dst)); + default: + errno = EAFNOSUPPORT; + return (-1); + } + /* NOTREACHED */ +} + +/* int + * inet_pton4(src, dst) + * like inet_aton() but without all the hexadecimal and shorthand. + * return: + * 1 if `src' is a valid dotted quad, else 0. + * notice: + * does not touch `dst' unless it's returning 1. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton4(src, dst) + const char *src; + u_char *dst; +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + u_char tmp[NS_INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) { + u_int new = *tp * 10 + (pch - digits); + + if (saw_digit && *tp == 0) + return (0); + if (new > 255) + return (0); + *tp = new; + if (!saw_digit) { + if (++octets > 4) + return (0); + saw_digit = 1; + } + } else if (ch == '.' && saw_digit) { + if (octets == 4) + return (0); + *++tp = 0; + saw_digit = 0; + } else + return (0); + } + if (octets < 4) + return (0); + memcpy(dst, tmp, NS_INADDRSZ); + return (1); +} + +/* int + * inet_pton6(src, dst) + * convert presentation level address to network order binary form. + * return: + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + * (1) does not touch `dst' unless it's returning 1. + * (2) :: in a full address is silently ignored. + * credit: + * inspired by Mark Andrews. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton6(src, dst) + const char *src; + u_char *dst; +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, seen_xdigits; + u_int val; + + memset((tp = tmp), '\0', NS_IN6ADDRSZ); + endp = tp + NS_IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return (0); + curtok = src; + seen_xdigits = 0; + val = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (++seen_xdigits > 4) + return (0); + continue; + } + if (ch == ':') { + curtok = src; + if (!seen_xdigits) { + if (colonp) + return (0); + colonp = tp; + continue; + } else if (*src == '\0') { + return (0); + } + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + seen_xdigits = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + inet_pton4(curtok, tp) > 0) { + tp += NS_INADDRSZ; + seen_xdigits = 0; + break; /*%< '\\0' was seen by inet_pton4(). */ + } + return (0); + } + if (seen_xdigits) { + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + } + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + if (tp == endp) + return (0); + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return (0); + memcpy(dst, tmp, NS_IN6ADDRSZ); + return (1); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/inet/nsap_addr.c b/contrib/bind-9.5.2/lib/bind/inet/nsap_addr.c new file mode 100644 index 0000000000..b6432e1e49 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/inet/nsap_addr.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: nsap_addr.c,v 1.5 2005/07/28 06:51:48 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include "port_before.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "port_after.h" + +static char +xtob(int c) { + return (c - (((c >= '0') && (c <= '9')) ? '0' : '7')); +} + +u_int +inet_nsap_addr(const char *ascii, u_char *binary, int maxlen) { + u_char c, nib; + u_int len = 0; + + if (ascii[0] != '0' || (ascii[1] != 'x' && ascii[1] != 'X')) + return (0); + ascii += 2; + + while ((c = *ascii++) != '\0' && len < (u_int)maxlen) { + if (c == '.' || c == '+' || c == '/') + continue; + if (!isascii(c)) + return (0); + if (islower(c)) + c = toupper(c); + if (isxdigit(c)) { + nib = xtob(c); + c = *ascii++; + if (c != '\0') { + c = toupper(c); + if (isxdigit(c)) { + *binary++ = (nib << 4) | xtob(c); + len++; + } else + return (0); + } + else + return (0); + } + else + return (0); + } + return (len); +} + +char * +inet_nsap_ntoa(int binlen, const u_char *binary, char *ascii) { + int nib; + int i; + char *tmpbuf = inet_nsap_ntoa_tmpbuf; + char *start; + + if (ascii) + start = ascii; + else { + ascii = tmpbuf; + start = tmpbuf; + } + + *ascii++ = '0'; + *ascii++ = 'x'; + + if (binlen > 255) + binlen = 255; + + for (i = 0; i < binlen; i++) { + nib = *binary >> 4; + *ascii++ = nib + (nib < 10 ? '0' : '7'); + nib = *binary++ & 0x0f; + *ascii++ = nib + (nib < 10 ? '0' : '7'); + if (((i % 2) == 0 && (i + 1) < binlen)) + *ascii++ = '.'; + } + *ascii = '\0'; + return (start); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/dns.c b/contrib/bind-9.5.2/lib/bind/irs/dns.c new file mode 100644 index 0000000000..cbea94680e --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/dns.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: dns.c,v 1.5 2006/03/09 23:57:56 marka Exp $"; +#endif + +/*! \file + * \brief + * dns.c --- this is the top-level accessor function for the dns + */ + +#include "port_before.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "hesiod.h" +#include "dns_p.h" + +/* forward */ + +static void dns_close(struct irs_acc *); +static struct __res_state * dns_res_get(struct irs_acc *); +static void dns_res_set(struct irs_acc *, struct __res_state *, + void (*)(void *)); + +/* public */ + +struct irs_acc * +irs_dns_acc(const char *options) { + struct irs_acc *acc; + struct dns_p *dns; + + UNUSED(options); + + if (!(acc = memget(sizeof *acc))) { + errno = ENOMEM; + return (NULL); + } + memset(acc, 0x5e, sizeof *acc); + if (!(dns = memget(sizeof *dns))) { + errno = ENOMEM; + memput(acc, sizeof *acc); + return (NULL); + } + memset(dns, 0x5e, sizeof *dns); + dns->res = NULL; + dns->free_res = NULL; + if (hesiod_init(&dns->hes_ctx) < 0) { + /* + * We allow the dns accessor class to initialize + * despite hesiod failing to initialize correctly, + * since dns host queries don't depend on hesiod. + */ + dns->hes_ctx = NULL; + } + acc->private = dns; +#ifdef WANT_IRS_GR + acc->gr_map = irs_dns_gr; +#else + acc->gr_map = NULL; +#endif +#ifdef WANT_IRS_PW + acc->pw_map = irs_dns_pw; +#else + acc->pw_map = NULL; +#endif + acc->sv_map = irs_dns_sv; + acc->pr_map = irs_dns_pr; + acc->ho_map = irs_dns_ho; + acc->nw_map = irs_dns_nw; + acc->ng_map = irs_nul_ng; + acc->res_get = dns_res_get; + acc->res_set = dns_res_set; + acc->close = dns_close; + return (acc); +} + +/* methods */ +static struct __res_state * +dns_res_get(struct irs_acc *this) { + struct dns_p *dns = (struct dns_p *)this->private; + + if (dns->res == NULL) { + struct __res_state *res; + res = (struct __res_state *)malloc(sizeof *res); + if (res == NULL) + return (NULL); + memset(res, 0, sizeof *res); + dns_res_set(this, res, free); + } + + if ((dns->res->options & RES_INIT) == 0U && + res_ninit(dns->res) < 0) + return (NULL); + + return (dns->res); +} + +static void +dns_res_set(struct irs_acc *this, struct __res_state *res, + void (*free_res)(void *)) { + struct dns_p *dns = (struct dns_p *)this->private; + + if (dns->res && dns->free_res) { + res_nclose(dns->res); + (*dns->free_res)(dns->res); + } + dns->res = res; + dns->free_res = free_res; +} + +static void +dns_close(struct irs_acc *this) { + struct dns_p *dns; + + dns = (struct dns_p *)this->private; + if (dns->res && dns->free_res) + (*dns->free_res)(dns->res); + if (dns->hes_ctx) + hesiod_end(dns->hes_ctx); + memput(dns, sizeof *dns); + memput(this, sizeof *this); +} + diff --git a/contrib/bind-9.5.2/lib/bind/irs/dns_gr.c b/contrib/bind-9.5.2/lib/bind/irs/dns_gr.c new file mode 100644 index 0000000000..629d2fb173 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/dns_gr.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: dns_gr.c,v 1.4 2005/04/27 04:56:21 sra Exp $"; +#endif + +/*! \file + * \brief + * dns_gr.c --- this file contains the functions for accessing + * group information from Hesiod. + */ + +#include "port_before.h" + +#ifndef WANT_IRS_GR +static int __bind_irs_gr_unneeded; +#else + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "hesiod.h" +#include "dns_p.h" + +/* Types. */ + +struct pvt { + /* + * This is our private accessor data. It has a shared hesiod context. + */ + struct dns_p * dns; + /* + * Need space to store the entries read from the group file. + * The members list also needs space per member, and the + * strings making up the user names must be allocated + * somewhere. Rather than doing lots of small allocations, + * we keep one buffer and resize it as needed. + */ + struct group group; + size_t nmemb; /*%< Malloc'd max index of gr_mem[]. */ + char * membuf; + size_t membufsize; +}; + +/* Forward. */ + +static struct group * gr_next(struct irs_gr *); +static struct group * gr_byname(struct irs_gr *, const char *); +static struct group * gr_bygid(struct irs_gr *, gid_t); +static void gr_rewind(struct irs_gr *); +static void gr_close(struct irs_gr *); +static int gr_list(struct irs_gr *, const char *, + gid_t, gid_t *, int *); +static void gr_minimize(struct irs_gr *); +static struct __res_state * gr_res_get(struct irs_gr *); +static void gr_res_set(struct irs_gr *, + struct __res_state *, + void (*)(void *)); + +static struct group * get_hes_group(struct irs_gr *this, + const char *name, + const char *type); + +/* Public. */ + +struct irs_gr * +irs_dns_gr(struct irs_acc *this) { + struct dns_p *dns = (struct dns_p *)this->private; + struct irs_gr *gr; + struct pvt *pvt; + + if (!dns || !dns->hes_ctx) { + errno = ENODEV; + return (NULL); + } + if (!(pvt = memget(sizeof *pvt))) { + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + pvt->dns = dns; + if (!(gr = memget(sizeof *gr))) { + memput(pvt, sizeof *pvt); + errno = ENOMEM; + return (NULL); + } + memset(gr, 0x5e, sizeof *gr); + gr->private = pvt; + gr->next = gr_next; + gr->byname = gr_byname; + gr->bygid = gr_bygid; + gr->rewind = gr_rewind; + gr->close = gr_close; + gr->list = gr_list; + gr->minimize = gr_minimize; + gr->res_get = gr_res_get; + gr->res_set = gr_res_set; + return (gr); +} + +/* methods */ + +static void +gr_close(struct irs_gr *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->group.gr_mem) + free(pvt->group.gr_mem); + if (pvt->membuf) + free(pvt->membuf); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct group * +gr_next(struct irs_gr *this) { + + UNUSED(this); + + return (NULL); +} + +static struct group * +gr_byname(struct irs_gr *this, const char *name) { + return (get_hes_group(this, name, "group")); +} + +static struct group * +gr_bygid(struct irs_gr *this, gid_t gid) { + char name[32]; + + sprintf(name, "%ld", (long)gid); + return (get_hes_group(this, name, "gid")); +} + +static void +gr_rewind(struct irs_gr *this) { + + UNUSED(this); + + /* NOOP */ +} + +static int +gr_list(struct irs_gr *this, const char *name, + gid_t basegid, gid_t *groups, int *ngroups) +{ + UNUSED(this); + UNUSED(name); + UNUSED(basegid); + UNUSED(groups); + + *ngroups = 0; + /* There's some way to do this in Hesiod. */ + return (-1); +} + +static void +gr_minimize(struct irs_gr *this) { + + UNUSED(this); + /* NOOP */ +} + +/* Private. */ + +static struct group * +get_hes_group(struct irs_gr *this, const char *name, const char *type) { + struct pvt *pvt = (struct pvt *)this->private; + char **hes_list, *cp, **new; + size_t num_members = 0; + u_long t; + + hes_list = hesiod_resolve(pvt->dns->hes_ctx, name, type); + if (!hes_list) + return (NULL); + + /* + * Copy the returned hesiod string into storage space. + */ + if (pvt->membuf) + free(pvt->membuf); + pvt->membuf = strdup(*hes_list); + hesiod_free_list(pvt->dns->hes_ctx, hes_list); + + cp = pvt->membuf; + pvt->group.gr_name = cp; + if (!(cp = strchr(cp, ':'))) + goto cleanup; + *cp++ = '\0'; + + pvt->group.gr_passwd = cp; + if (!(cp = strchr(cp, ':'))) + goto cleanup; + *cp++ = '\0'; + + errno = 0; + t = strtoul(cp, NULL, 10); + if (errno == ERANGE) + goto cleanup; + pvt->group.gr_gid = (gid_t) t; + if (!(cp = strchr(cp, ':'))) + goto cleanup; + cp++; + + /* + * Parse the members out. + */ + while (*cp) { + if (num_members+1 >= pvt->nmemb || pvt->group.gr_mem == NULL) { + pvt->nmemb += 10; + new = realloc(pvt->group.gr_mem, + pvt->nmemb * sizeof(char *)); + if (new == NULL) + goto cleanup; + pvt->group.gr_mem = new; + } + pvt->group.gr_mem[num_members++] = cp; + if (!(cp = strchr(cp, ','))) + break; + *cp++ = '\0'; + } + if (!pvt->group.gr_mem) { + pvt->group.gr_mem = malloc(sizeof(char*)); + if (!pvt->group.gr_mem) + goto cleanup; + } + pvt->group.gr_mem[num_members] = NULL; + + return (&pvt->group); + + cleanup: + if (pvt->group.gr_mem) { + free(pvt->group.gr_mem); + pvt->group.gr_mem = NULL; + } + if (pvt->membuf) { + free(pvt->membuf); + pvt->membuf = NULL; + } + return (NULL); +} + +static struct __res_state * +gr_res_get(struct irs_gr *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct dns_p *dns = pvt->dns; + + return (__hesiod_res_get(dns->hes_ctx)); +} + +static void +gr_res_set(struct irs_gr *this, struct __res_state * res, + void (*free_res)(void *)) { + struct pvt *pvt = (struct pvt *)this->private; + struct dns_p *dns = pvt->dns; + + __hesiod_res_set(dns->hes_ctx, res, free_res); +} + +#endif /* WANT_IRS_GR */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/dns_ho.c b/contrib/bind-9.5.2/lib/bind/irs/dns_ho.c new file mode 100644 index 0000000000..eed8dd7698 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/dns_ho.c @@ -0,0 +1,1143 @@ +/* + * Copyright (c) 1985, 1988, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +/* from gethostnamadr.c 8.1 (Berkeley) 6/4/93 */ +/* BIND Id: gethnamaddr.c,v 8.15 1996/05/22 04:56:30 vixie Exp $ */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: dns_ho.c,v 1.21.246.1 2008/09/24 05:41:39 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* Imports. */ + +#include "port_before.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "dns_p.h" + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) sprintf x +#endif + +/* Definitions. */ + +#define MAXALIASES 35 +#define MAXADDRS 35 + +#define MAXPACKET (65535) /*%< Maximum TCP message size */ +#define BOUNDS_CHECK(ptr, count) \ + if ((ptr) + (count) > eom) { \ + had_error++; \ + continue; \ + } else (void)0 + +typedef union { + HEADER hdr; + u_char buf[MAXPACKET]; +} querybuf; + +struct dns_res_target { + struct dns_res_target *next; + querybuf qbuf; /*%< query buffer */ + u_char *answer; /*%< buffer to put answer */ + int anslen; /*%< size of answer buffer */ + int qclass, qtype; /*%< class and type of query */ + int action; /*%< condition whether query is really issued */ + char qname[MAXDNAME +1]; /*%< domain name */ +#if 0 + int n; /*%< result length */ +#endif +}; +enum {RESTGT_DOALWAYS, RESTGT_AFTERFAILURE, RESTGT_IGNORE}; +enum {RESQRY_SUCCESS, RESQRY_FAIL}; + +struct pvt { + struct hostent host; + char * h_addr_ptrs[MAXADDRS + 1]; + char * host_aliases[MAXALIASES]; + char hostbuf[8*1024]; + u_char host_addr[16]; /*%< IPv4 or IPv6 */ + struct __res_state *res; + void (*free_res)(void *); +}; + +typedef union { + int32_t al; + char ac; +} align; + +static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff }; +static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 }; +/* Note: the IPv6 loopback address is in the "tunnel" space */ +static const u_char v6local[] = { 0,0, 0,1 }; /*%< last 4 bytes of IPv6 addr */ +/* Forwards. */ + +static void ho_close(struct irs_ho *this); +static struct hostent * ho_byname(struct irs_ho *this, const char *name); +static struct hostent * ho_byname2(struct irs_ho *this, const char *name, + int af); +static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr, + int len, int af); +static struct hostent * ho_next(struct irs_ho *this); +static void ho_rewind(struct irs_ho *this); +static void ho_minimize(struct irs_ho *this); +static struct __res_state * ho_res_get(struct irs_ho *this); +static void ho_res_set(struct irs_ho *this, + struct __res_state *res, + void (*free_res)(void *)); +static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name, + const struct addrinfo *pai); + +static void map_v4v6_hostent(struct hostent *hp, char **bp, + char *ep); +static void addrsort(res_state, char **, int); +static struct hostent * gethostans(struct irs_ho *this, + const u_char *ansbuf, int anslen, + const char *qname, int qtype, + int af, int size, + struct addrinfo **ret_aip, + const struct addrinfo *pai); +static int add_hostent(struct pvt *pvt, char *bp, char **hap, + struct addrinfo *ai); +static int init(struct irs_ho *this); + +/* Exports. */ + +struct irs_ho * +irs_dns_ho(struct irs_acc *this) { + struct irs_ho *ho; + struct pvt *pvt; + + UNUSED(this); + + if (!(pvt = memget(sizeof *pvt))) { + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + + if (!(ho = memget(sizeof *ho))) { + memput(pvt, sizeof *pvt); + errno = ENOMEM; + return (NULL); + } + memset(ho, 0x5e, sizeof *ho); + ho->private = pvt; + ho->close = ho_close; + ho->byname = ho_byname; + ho->byname2 = ho_byname2; + ho->byaddr = ho_byaddr; + ho->next = ho_next; + ho->rewind = ho_rewind; + ho->minimize = ho_minimize; + ho->res_get = ho_res_get; + ho->res_set = ho_res_set; + ho->addrinfo = ho_addrinfo; + return (ho); +} + +/* Methods. */ + +static void +ho_close(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + + ho_minimize(this); + if (pvt->res && pvt->free_res) + (*pvt->free_res)(pvt->res); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct hostent * +ho_byname(struct irs_ho *this, const char *name) { + struct pvt *pvt = (struct pvt *)this->private; + struct hostent *hp; + + if (init(this) == -1) + return (NULL); + + if (pvt->res->options & RES_USE_INET6) { + hp = ho_byname2(this, name, AF_INET6); + if (hp) + return (hp); + } + return (ho_byname2(this, name, AF_INET)); +} + +static struct hostent * +ho_byname2(struct irs_ho *this, const char *name, int af) +{ + struct pvt *pvt = (struct pvt *)this->private; + struct hostent *hp = NULL; + int n, size; + char tmp[NS_MAXDNAME]; + const char *cp; + struct addrinfo ai; + struct dns_res_target *q, *p; + int querystate = RESQRY_FAIL; + + if (init(this) == -1) + return (NULL); + + q = memget(sizeof(*q)); + if (q == NULL) { + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + errno = ENOMEM; + goto cleanup; + } + memset(q, 0, sizeof(*q)); + + switch (af) { + case AF_INET: + size = INADDRSZ; + q->qclass = C_IN; + q->qtype = T_A; + q->answer = q->qbuf.buf; + q->anslen = sizeof(q->qbuf); + q->action = RESTGT_DOALWAYS; + break; + case AF_INET6: + size = IN6ADDRSZ; + q->qclass = C_IN; + q->qtype = T_AAAA; + q->answer = q->qbuf.buf; + q->anslen = sizeof(q->qbuf); + q->action = RESTGT_DOALWAYS; + break; + default: + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + errno = EAFNOSUPPORT; + hp = NULL; + goto cleanup; + } + + /* + * if there aren't any dots, it could be a user-level alias. + * this is also done in res_nquery() since we are not the only + * function that looks up host names. + */ + if (!strchr(name, '.') && (cp = res_hostalias(pvt->res, name, + tmp, sizeof tmp))) + name = cp; + + for (p = q; p; p = p->next) { + switch(p->action) { + case RESTGT_DOALWAYS: + break; + case RESTGT_AFTERFAILURE: + if (querystate == RESQRY_SUCCESS) + continue; + break; + case RESTGT_IGNORE: + continue; + } + + if ((n = res_nsearch(pvt->res, name, p->qclass, p->qtype, + p->answer, p->anslen)) < 0) { + querystate = RESQRY_FAIL; + continue; + } + + memset(&ai, 0, sizeof(ai)); + ai.ai_family = af; + if ((hp = gethostans(this, p->answer, n, name, p->qtype, + af, size, NULL, + (const struct addrinfo *)&ai)) != NULL) + goto cleanup; /*%< no more loop is necessary */ + querystate = RESQRY_FAIL; + continue; + } + + cleanup: + if (q != NULL) + memput(q, sizeof(*q)); + return(hp); +} + +static struct hostent * +ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) +{ + struct pvt *pvt = (struct pvt *)this->private; + const u_char *uaddr = addr; + char *qp; + struct hostent *hp = NULL; + struct addrinfo ai; + struct dns_res_target *q, *q2, *p; + int n, size, i; + int querystate = RESQRY_FAIL; + + if (init(this) == -1) + return (NULL); + + q = memget(sizeof(*q)); + q2 = memget(sizeof(*q2)); + if (q == NULL || q2 == NULL) { + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + errno = ENOMEM; + goto cleanup; + } + memset(q, 0, sizeof(*q)); + memset(q2, 0, sizeof(*q2)); + + if (af == AF_INET6 && len == IN6ADDRSZ && + (!memcmp(uaddr, mapped, sizeof mapped) || + (!memcmp(uaddr, tunnelled, sizeof tunnelled) && + memcmp(&uaddr[sizeof tunnelled], v6local, sizeof(v6local))))) { + /* Unmap. */ + addr = (const char *)addr + sizeof mapped; + uaddr += sizeof mapped; + af = AF_INET; + len = INADDRSZ; + } + switch (af) { + case AF_INET: + size = INADDRSZ; + q->qclass = C_IN; + q->qtype = T_PTR; + q->answer = q->qbuf.buf; + q->anslen = sizeof(q->qbuf); + q->action = RESTGT_DOALWAYS; + break; + case AF_INET6: + size = IN6ADDRSZ; + q->qclass = C_IN; + q->qtype = T_PTR; + q->answer = q->qbuf.buf; + q->anslen = sizeof(q->qbuf); + q->next = q2; + q->action = RESTGT_DOALWAYS; + q2->qclass = C_IN; + q2->qtype = T_PTR; + q2->answer = q2->qbuf.buf; + q2->anslen = sizeof(q2->qbuf); + if ((pvt->res->options & RES_NO_NIBBLE2) != 0U) + q2->action = RESTGT_IGNORE; + else + q2->action = RESTGT_AFTERFAILURE; + break; + default: + errno = EAFNOSUPPORT; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + hp = NULL; + goto cleanup; + } + if (size > len) { + errno = EINVAL; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + hp = NULL; + goto cleanup; + } + switch (af) { + case AF_INET: + qp = q->qname; + (void) sprintf(qp, "%u.%u.%u.%u.in-addr.arpa", + (uaddr[3] & 0xff), + (uaddr[2] & 0xff), + (uaddr[1] & 0xff), + (uaddr[0] & 0xff)); + break; + case AF_INET6: + if (q->action != RESTGT_IGNORE) { + const char *nibsuff = res_get_nibblesuffix(pvt->res); + qp = q->qname; + for (n = IN6ADDRSZ - 1; n >= 0; n--) { + i = SPRINTF((qp, "%x.%x.", + uaddr[n] & 0xf, + (uaddr[n] >> 4) & 0xf)); + if (i != 4) + abort(); + qp += i; + } + if (strlen(q->qname) + strlen(nibsuff) + 1 > + sizeof q->qname) { + errno = ENAMETOOLONG; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + hp = NULL; + goto cleanup; + } + strcpy(qp, nibsuff); /* (checked) */ + } + if (q2->action != RESTGT_IGNORE) { + const char *nibsuff2 = res_get_nibblesuffix2(pvt->res); + qp = q2->qname; + for (n = IN6ADDRSZ - 1; n >= 0; n--) { + i = SPRINTF((qp, "%x.%x.", + uaddr[n] & 0xf, + (uaddr[n] >> 4) & 0xf)); + if (i != 4) + abort(); + qp += i; + } + if (strlen(q2->qname) + strlen(nibsuff2) + 1 > + sizeof q2->qname) { + errno = ENAMETOOLONG; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + hp = NULL; + goto cleanup; + } + strcpy(qp, nibsuff2); /* (checked) */ + } + break; + default: + abort(); + } + + for (p = q; p; p = p->next) { + switch(p->action) { + case RESTGT_DOALWAYS: + break; + case RESTGT_AFTERFAILURE: + if (querystate == RESQRY_SUCCESS) + continue; + break; + case RESTGT_IGNORE: + continue; + } + + if ((n = res_nquery(pvt->res, p->qname, p->qclass, p->qtype, + p->answer, p->anslen)) < 0) { + querystate = RESQRY_FAIL; + continue; + } + + memset(&ai, 0, sizeof(ai)); + ai.ai_family = af; + hp = gethostans(this, p->answer, n, p->qname, T_PTR, af, size, + NULL, (const struct addrinfo *)&ai); + if (!hp) { + querystate = RESQRY_FAIL; + continue; + } + + memcpy(pvt->host_addr, addr, len); + pvt->h_addr_ptrs[0] = (char *)pvt->host_addr; + pvt->h_addr_ptrs[1] = NULL; + if (af == AF_INET && (pvt->res->options & RES_USE_INET6)) { + map_v4v6_address((char*)pvt->host_addr, + (char*)pvt->host_addr); + pvt->host.h_addrtype = AF_INET6; + pvt->host.h_length = IN6ADDRSZ; + } + + RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS); + goto cleanup; /*%< no more loop is necessary. */ + } + hp = NULL; /*%< H_ERRNO was set by subroutines */ + cleanup: + if (q != NULL) + memput(q, sizeof(*q)); + if (q2 != NULL) + memput(q2, sizeof(*q2)); + return(hp); +} + +static struct hostent * +ho_next(struct irs_ho *this) { + + UNUSED(this); + + return (NULL); +} + +static void +ho_rewind(struct irs_ho *this) { + + UNUSED(this); + + /* NOOP */ +} + +static void +ho_minimize(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->res) + res_nclose(pvt->res); +} + +static struct __res_state * +ho_res_get(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->res) { + struct __res_state *res; + res = (struct __res_state *)malloc(sizeof *res); + if (!res) { + errno = ENOMEM; + return (NULL); + } + memset(res, 0, sizeof *res); + ho_res_set(this, res, free); + } + + return (pvt->res); +} + +/* XXX */ +extern struct addrinfo *addr2addrinfo __P((const struct addrinfo *, + const char *)); + +static struct addrinfo * +ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai) +{ + struct pvt *pvt = (struct pvt *)this->private; + int n; + char tmp[NS_MAXDNAME]; + const char *cp; + struct dns_res_target *q, *q2, *p; + struct addrinfo sentinel, *cur; + int querystate = RESQRY_FAIL; + + if (init(this) == -1) + return (NULL); + + memset(&sentinel, 0, sizeof(sentinel)); + cur = &sentinel; + + q = memget(sizeof(*q)); + q2 = memget(sizeof(*q2)); + if (q == NULL || q2 == NULL) { + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + errno = ENOMEM; + goto cleanup; + } + memset(q, 0, sizeof(*q2)); + memset(q2, 0, sizeof(*q2)); + + switch (pai->ai_family) { + case AF_UNSPEC: + /* prefer IPv6 */ + q->qclass = C_IN; + q->qtype = T_AAAA; + q->answer = q->qbuf.buf; + q->anslen = sizeof(q->qbuf); + q->next = q2; + q->action = RESTGT_DOALWAYS; + q2->qclass = C_IN; + q2->qtype = T_A; + q2->answer = q2->qbuf.buf; + q2->anslen = sizeof(q2->qbuf); + q2->action = RESTGT_DOALWAYS; + break; + case AF_INET: + q->qclass = C_IN; + q->qtype = T_A; + q->answer = q->qbuf.buf; + q->anslen = sizeof(q->qbuf); + q->action = RESTGT_DOALWAYS; + break; + case AF_INET6: + q->qclass = C_IN; + q->qtype = T_AAAA; + q->answer = q->qbuf.buf; + q->anslen = sizeof(q->qbuf); + q->action = RESTGT_DOALWAYS; + break; + default: + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); /*%< better error? */ + goto cleanup; + } + + /* + * if there aren't any dots, it could be a user-level alias. + * this is also done in res_nquery() since we are not the only + * function that looks up host names. + */ + if (!strchr(name, '.') && (cp = res_hostalias(pvt->res, name, + tmp, sizeof tmp))) + name = cp; + + for (p = q; p; p = p->next) { + struct addrinfo *ai; + + switch(p->action) { + case RESTGT_DOALWAYS: + break; + case RESTGT_AFTERFAILURE: + if (querystate == RESQRY_SUCCESS) + continue; + break; + case RESTGT_IGNORE: + continue; + } + + if ((n = res_nsearch(pvt->res, name, p->qclass, p->qtype, + p->answer, p->anslen)) < 0) { + querystate = RESQRY_FAIL; + continue; + } + (void)gethostans(this, p->answer, n, name, p->qtype, + pai->ai_family, /*%< XXX: meaningless */ + 0, &ai, pai); + if (ai) { + querystate = RESQRY_SUCCESS; + cur->ai_next = ai; + while (cur->ai_next) + cur = cur->ai_next; + } else + querystate = RESQRY_FAIL; + } + + cleanup: + if (q != NULL) + memput(q, sizeof(*q)); + if (q2 != NULL) + memput(q2, sizeof(*q2)); + return(sentinel.ai_next); +} + +static void +ho_res_set(struct irs_ho *this, struct __res_state *res, + void (*free_res)(void *)) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->res && pvt->free_res) { + res_nclose(pvt->res); + (*pvt->free_res)(pvt->res); + } + + pvt->res = res; + pvt->free_res = free_res; +} + +/* Private. */ + +static struct hostent * +gethostans(struct irs_ho *this, + const u_char *ansbuf, int anslen, const char *qname, int qtype, + int af, int size, /*!< meaningless for addrinfo cases */ + struct addrinfo **ret_aip, const struct addrinfo *pai) +{ + struct pvt *pvt = (struct pvt *)this->private; + int type, class, ancount, qdcount, n, haveanswer, had_error; + int error = NETDB_SUCCESS; + int (*name_ok)(const char *); + const HEADER *hp; + const u_char *eom; + const u_char *eor; + const u_char *cp; + const char *tname; + const char *hname; + char *bp, *ep, **ap, **hap; + char tbuf[MAXDNAME+1]; + struct addrinfo sentinel, *cur, ai; + + if (pai == NULL) abort(); + if (ret_aip != NULL) + *ret_aip = NULL; + memset(&sentinel, 0, sizeof(sentinel)); + cur = &sentinel; + + tname = qname; + eom = ansbuf + anslen; + switch (qtype) { + case T_A: + case T_AAAA: + case T_ANY: /*%< use T_ANY only for T_A/T_AAAA lookup */ + name_ok = res_hnok; + break; + case T_PTR: + name_ok = res_dnok; + break; + default: + abort(); + } + + pvt->host.h_addrtype = af; + pvt->host.h_length = size; + hname = pvt->host.h_name = NULL; + + /* + * Find first satisfactory answer. + */ + if (ansbuf + HFIXEDSZ > eom) { + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); + return (NULL); + } + hp = (const HEADER *)ansbuf; + ancount = ntohs(hp->ancount); + qdcount = ntohs(hp->qdcount); + bp = pvt->hostbuf; + ep = pvt->hostbuf + sizeof(pvt->hostbuf); + cp = ansbuf + HFIXEDSZ; + if (qdcount != 1) { + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); + return (NULL); + } + n = dn_expand(ansbuf, eom, cp, bp, ep - bp); + if (n < 0 || !maybe_ok(pvt->res, bp, name_ok)) { + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); + return (NULL); + } + cp += n + QFIXEDSZ; + if (cp > eom) { + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); + return (NULL); + } + if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { + /* res_nsend() has already verified that the query name is the + * same as the one we sent; this just gets the expanded name + * (i.e., with the succeeding search-domain tacked on). + */ + n = strlen(bp) + 1; /*%< for the \\0 */ + if (n > MAXHOSTNAMELEN) { + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); + return (NULL); + } + pvt->host.h_name = bp; + hname = bp; + bp += n; + /* The qname can be abbreviated, but hname is now absolute. */ + qname = pvt->host.h_name; + } + ap = pvt->host_aliases; + *ap = NULL; + pvt->host.h_aliases = pvt->host_aliases; + hap = pvt->h_addr_ptrs; + *hap = NULL; + pvt->host.h_addr_list = pvt->h_addr_ptrs; + haveanswer = 0; + had_error = 0; + while (ancount-- > 0 && cp < eom && !had_error) { + n = dn_expand(ansbuf, eom, cp, bp, ep - bp); + if (n < 0 || !maybe_ok(pvt->res, bp, name_ok)) { + had_error++; + continue; + } + cp += n; /*%< name */ + BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); + type = ns_get16(cp); + cp += INT16SZ; /*%< type */ + class = ns_get16(cp); + cp += INT16SZ + INT32SZ; /*%< class, TTL */ + n = ns_get16(cp); + cp += INT16SZ; /*%< len */ + BOUNDS_CHECK(cp, n); + if (class != C_IN) { + cp += n; + continue; + } + eor = cp + n; + if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && + type == T_CNAME) { + if (haveanswer) { + int level = LOG_CRIT; +#ifdef LOG_SECURITY + level |= LOG_SECURITY; +#endif + syslog(level, + "gethostans: possible attempt to exploit buffer overflow while looking up %s", + *qname ? qname : "."); + } + n = dn_expand(ansbuf, eor, cp, tbuf, sizeof tbuf); + if (n < 0 || !maybe_ok(pvt->res, tbuf, name_ok)) { + had_error++; + continue; + } + cp += n; + /* Store alias. */ + if (ap >= &pvt->host_aliases[MAXALIASES-1]) + continue; + *ap++ = bp; + n = strlen(bp) + 1; /*%< for the \\0 */ + bp += n; + /* Get canonical name. */ + n = strlen(tbuf) + 1; /*%< for the \\0 */ + if (n > (ep - bp) || n > MAXHOSTNAMELEN) { + had_error++; + continue; + } + strcpy(bp, tbuf); /* (checked) */ + pvt->host.h_name = bp; + hname = bp; + bp += n; + continue; + } + if (qtype == T_PTR && type == T_CNAME) { + n = dn_expand(ansbuf, eor, cp, tbuf, sizeof tbuf); + if (n < 0 || !maybe_dnok(pvt->res, tbuf)) { + had_error++; + continue; + } + cp += n; +#ifdef RES_USE_DNAME + if ((pvt->res->options & RES_USE_DNAME) != 0U) +#endif + { + /* + * We may be able to check this regardless + * of the USE_DNAME bit, but we add the check + * for now since the DNAME support is + * experimental. + */ + if (ns_samename(tname, bp) != 1) + continue; + } + /* Get canonical name. */ + n = strlen(tbuf) + 1; /*%< for the \\0 */ + if (n > (ep - bp)) { + had_error++; + continue; + } + strcpy(bp, tbuf); /* (checked) */ + tname = bp; + bp += n; + continue; + } + if (qtype == T_ANY) { + if (!(type == T_A || type == T_AAAA)) { + cp += n; + continue; + } + } else if (type != qtype) { + cp += n; + continue; + } + switch (type) { + case T_PTR: + if (ret_aip != NULL) { + /* addrinfo never needs T_PTR */ + cp += n; + continue; + } + if (ns_samename(tname, bp) != 1) { + cp += n; + continue; + } + n = dn_expand(ansbuf, eor, cp, bp, ep - bp); + if (n < 0 || !maybe_hnok(pvt->res, bp) || + n >= MAXHOSTNAMELEN) { + had_error++; + break; + } + cp += n; + if (!haveanswer) { + pvt->host.h_name = bp; + hname = bp; + } + else if (ap < &pvt->host_aliases[MAXALIASES-1]) + *ap++ = bp; + else + n = -1; + if (n != -1) { + n = strlen(bp) + 1; /*%< for the \\0 */ + bp += n; + } + break; + case T_A: + case T_AAAA: + if (ns_samename(hname, bp) != 1) { + cp += n; + continue; + } + if (type == T_A && n != INADDRSZ) { + cp += n; + continue; + } + if (type == T_AAAA && n != IN6ADDRSZ) { + cp += n; + continue; + } + + /* make addrinfo. don't overwrite constant PAI */ + ai = *pai; + ai.ai_family = (type == T_AAAA) ? AF_INET6 : AF_INET; + cur->ai_next = addr2addrinfo( + (const struct addrinfo *)&ai, + (const char *)cp); + if (cur->ai_next == NULL) + had_error++; + + if (!haveanswer) { + int nn; + + nn = strlen(bp) + 1; /*%< for the \\0 */ + if (nn >= MAXHOSTNAMELEN) { + cp += n; + had_error++; + continue; + } + pvt->host.h_name = bp; + hname = bp; + bp += nn; + } + /* Ensure alignment. */ + bp = (char *)(((u_long)bp + (sizeof(align) - 1)) & + ~(sizeof(align) - 1)); + /* Avoid overflows. */ + if (bp + n > &pvt->hostbuf[sizeof(pvt->hostbuf) - 1]) { + had_error++; + continue; + } + if (ret_aip) { /*%< need addrinfo. keep it. */ + while (cur->ai_next) + cur = cur->ai_next; + } else if (cur->ai_next) { /*%< need hostent */ + struct addrinfo *aip = cur->ai_next; + + for (aip = cur->ai_next; aip; + aip = aip->ai_next) { + int m; + + m = add_hostent(pvt, bp, hap, aip); + if (m < 0) { + had_error++; + break; + } + if (m == 0) + continue; + if (hap < &pvt->h_addr_ptrs[MAXADDRS]) + hap++; + *hap = NULL; + bp += m; + } + + freeaddrinfo(cur->ai_next); + cur->ai_next = NULL; + } + cp += n; + break; + default: + abort(); + } + if (!had_error) + haveanswer++; + } + if (haveanswer) { + if (ret_aip == NULL) { + *ap = NULL; + *hap = NULL; + + if (pvt->res->nsort && hap != pvt->h_addr_ptrs && + qtype == T_A) + addrsort(pvt->res, pvt->h_addr_ptrs, + hap - pvt->h_addr_ptrs); + if (pvt->host.h_name == NULL) { + n = strlen(qname) + 1; /*%< for the \\0 */ + if (n > (ep - bp) || n >= MAXHOSTNAMELEN) + goto no_recovery; + strcpy(bp, qname); /* (checked) */ + pvt->host.h_name = bp; + bp += n; + } + if (pvt->res->options & RES_USE_INET6) + map_v4v6_hostent(&pvt->host, &bp, ep); + RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS); + return (&pvt->host); + } else { + if ((pai->ai_flags & AI_CANONNAME) != 0) { + if (pvt->host.h_name == NULL) { + sentinel.ai_next->ai_canonname = + strdup(qname); + } + else { + sentinel.ai_next->ai_canonname = + strdup(pvt->host.h_name); + } + } + *ret_aip = sentinel.ai_next; + return(NULL); + } + } + no_recovery: + if (sentinel.ai_next) { + /* this should be impossible, but check it for safety */ + freeaddrinfo(sentinel.ai_next); + } + if (error == NETDB_SUCCESS) + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); + else + RES_SET_H_ERRNO(pvt->res, error); + return(NULL); +} + +static int +add_hostent(struct pvt *pvt, char *bp, char **hap, struct addrinfo *ai) +{ + int addrlen; + char *addrp; + const char **tap; + char *obp = bp; + + switch(ai->ai_addr->sa_family) { + case AF_INET6: + addrlen = IN6ADDRSZ; + addrp = (char *)&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr; + break; + case AF_INET: + addrlen = INADDRSZ; + addrp = (char *)&((struct sockaddr_in *)ai->ai_addr)->sin_addr; + break; + default: + return(-1); /*%< abort? */ + } + + /* Ensure alignment. */ + bp = (char *)(((u_long)bp + (sizeof(align) - 1)) & + ~(sizeof(align) - 1)); + /* Avoid overflows. */ + if (bp + addrlen > &pvt->hostbuf[sizeof(pvt->hostbuf) - 1]) + return(-1); + if (hap >= &pvt->h_addr_ptrs[MAXADDRS]) + return(0); /*%< fail, but not treat it as an error. */ + /* Suppress duplicates. */ + for (tap = (const char **)pvt->h_addr_ptrs; + *tap != NULL; + tap++) + if (memcmp(*tap, addrp, addrlen) == 0) + break; + if (*tap != NULL) + return (0); + + memcpy(*hap = bp, addrp, addrlen); + return((bp + addrlen) - obp); +} + +static void +map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep) { + char **ap; + + if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ) + return; + hp->h_addrtype = AF_INET6; + hp->h_length = IN6ADDRSZ; + for (ap = hp->h_addr_list; *ap; ap++) { + int i = (u_long)*bpp % sizeof(align); + + if (i != 0) + i = sizeof(align) - i; + + if ((ep - *bpp) < (i + IN6ADDRSZ)) { + /* Out of memory. Truncate address list here. */ + *ap = NULL; + return; + } + *bpp += i; + map_v4v6_address(*ap, *bpp); + *ap = *bpp; + *bpp += IN6ADDRSZ; + } +} + +static void +addrsort(res_state statp, char **ap, int num) { + int i, j, needsort = 0, aval[MAXADDRS]; + char **p; + + p = ap; + for (i = 0; i < num; i++, p++) { + for (j = 0 ; (unsigned)j < statp->nsort; j++) + if (statp->sort_list[j].addr.s_addr == + (((struct in_addr *)(*p))->s_addr & + statp->sort_list[j].mask)) + break; + aval[i] = j; + if (needsort == 0 && i > 0 && j < aval[i-1]) + needsort = i; + } + if (!needsort) + return; + + while (needsort < num) { + for (j = needsort - 1; j >= 0; j--) { + if (aval[j] > aval[j+1]) { + char *hp; + + i = aval[j]; + aval[j] = aval[j+1]; + aval[j+1] = i; + + hp = ap[j]; + ap[j] = ap[j+1]; + ap[j+1] = hp; + + } else + break; + } + needsort++; + } +} + +static int +init(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->res && !ho_res_get(this)) + return (-1); + if (((pvt->res->options & RES_INIT) == 0U) && + res_ninit(pvt->res) == -1) + return (-1); + return (0); +} diff --git a/contrib/bind-9.5.2/lib/bind/irs/dns_nw.c b/contrib/bind-9.5.2/lib/bind/irs/dns_nw.c new file mode 100644 index 0000000000..dc1e61739b --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/dns_nw.c @@ -0,0 +1,591 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: dns_nw.c,v 1.12 2005/04/27 04:56:22 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* Imports. */ + +#include "port_before.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "dns_p.h" + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) sprintf x +#endif + +/* Definitions. */ + +#define MAXALIASES 35 + +#define MAXPACKET (64*1024) + +struct pvt { + struct nwent net; + char * ali[MAXALIASES]; + char buf[BUFSIZ+1]; + struct __res_state * res; + void (*free_res)(void *); +}; + +typedef union { + long al; + char ac; +} align; + +enum by_what { by_addr, by_name }; + +/* Forwards. */ + +static void nw_close(struct irs_nw *); +static struct nwent * nw_byname(struct irs_nw *, const char *, int); +static struct nwent * nw_byaddr(struct irs_nw *, void *, int, int); +static struct nwent * nw_next(struct irs_nw *); +static void nw_rewind(struct irs_nw *); +static void nw_minimize(struct irs_nw *); +static struct __res_state * nw_res_get(struct irs_nw *this); +static void nw_res_set(struct irs_nw *this, + struct __res_state *res, + void (*free_res)(void *)); + +static struct nwent * get1101byaddr(struct irs_nw *, u_char *, int); +static struct nwent * get1101byname(struct irs_nw *, const char *); +static struct nwent * get1101answer(struct irs_nw *, + u_char *ansbuf, int anslen, + enum by_what by_what, + int af, const char *name, + const u_char *addr, int addrlen); +static struct nwent * get1101mask(struct irs_nw *this, struct nwent *); +static int make1101inaddr(const u_char *, int, char *, int); +static void normalize_name(char *name); +static int init(struct irs_nw *this); + +/* Exports. */ + +struct irs_nw * +irs_dns_nw(struct irs_acc *this) { + struct irs_nw *nw; + struct pvt *pvt; + + UNUSED(this); + + if (!(pvt = memget(sizeof *pvt))) { + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + if (!(nw = memget(sizeof *nw))) { + memput(pvt, sizeof *pvt); + errno = ENOMEM; + return (NULL); + } + memset(nw, 0x5e, sizeof *nw); + nw->private = pvt; + nw->close = nw_close; + nw->byname = nw_byname; + nw->byaddr = nw_byaddr; + nw->next = nw_next; + nw->rewind = nw_rewind; + nw->minimize = nw_minimize; + nw->res_get = nw_res_get; + nw->res_set = nw_res_set; + return (nw); +} + +/* Methods. */ + +static void +nw_close(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + nw_minimize(this); + + if (pvt->res && pvt->free_res) + (*pvt->free_res)(pvt->res); + + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct nwent * +nw_byname(struct irs_nw *this, const char *name, int af) { + struct pvt *pvt = (struct pvt *)this->private; + + if (init(this) == -1) + return (NULL); + + switch (af) { + case AF_INET: + return (get1101byname(this, name)); + default: + (void)NULL; + } + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + errno = EAFNOSUPPORT; + return (NULL); +} + +static struct nwent * +nw_byaddr(struct irs_nw *this, void *net, int len, int af) { + struct pvt *pvt = (struct pvt *)this->private; + + if (init(this) == -1) + return (NULL); + + switch (af) { + case AF_INET: + return (get1101byaddr(this, net, len)); + default: + (void)NULL; + } + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + errno = EAFNOSUPPORT; + return (NULL); +} + +static struct nwent * +nw_next(struct irs_nw *this) { + + UNUSED(this); + + return (NULL); +} + +static void +nw_rewind(struct irs_nw *this) { + UNUSED(this); + /* NOOP */ +} + +static void +nw_minimize(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->res) + res_nclose(pvt->res); +} + +static struct __res_state * +nw_res_get(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->res) { + struct __res_state *res; + res = (struct __res_state *)malloc(sizeof *res); + if (!res) { + errno = ENOMEM; + return (NULL); + } + memset(res, 0, sizeof *res); + nw_res_set(this, res, free); + } + + return (pvt->res); +} + +static void +nw_res_set(struct irs_nw *this, struct __res_state *res, + void (*free_res)(void *)) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->res && pvt->free_res) { + res_nclose(pvt->res); + (*pvt->free_res)(pvt->res); + } + + pvt->res = res; + pvt->free_res = free_res; +} + +/* Private. */ + +static struct nwent * +get1101byname(struct irs_nw *this, const char *name) { + struct pvt *pvt = (struct pvt *)this->private; + u_char *ansbuf; + int anslen; + struct nwent *result; + + ansbuf = memget(MAXPACKET); + if (ansbuf == NULL) { + errno = ENOMEM; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + return (NULL); + } + anslen = res_nsearch(pvt->res, name, C_IN, T_PTR, ansbuf, MAXPACKET); + if (anslen < 0) { + memput(ansbuf, MAXPACKET); + return (NULL); + } + result = get1101mask(this, get1101answer(this, ansbuf, anslen, by_name, + AF_INET, name, NULL, 0)); + memput(ansbuf, MAXPACKET); + return (result); +} + +static struct nwent * +get1101byaddr(struct irs_nw *this, u_char *net, int len) { + struct pvt *pvt = (struct pvt *)this->private; + char qbuf[sizeof "255.255.255.255.in-addr.arpa"]; + struct nwent *result; + u_char *ansbuf; + int anslen; + + if (len < 1 || len > 32) { + errno = EINVAL; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + return (NULL); + } + if (make1101inaddr(net, len, qbuf, sizeof qbuf) < 0) + return (NULL); + ansbuf = memget(MAXPACKET); + if (ansbuf == NULL) { + errno = ENOMEM; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + return (NULL); + } + anslen = res_nquery(pvt->res, qbuf, C_IN, T_PTR, ansbuf, MAXPACKET); + if (anslen < 0) { + memput(ansbuf, MAXPACKET); + return (NULL); + } + result = get1101mask(this, get1101answer(this, ansbuf, anslen, by_addr, + AF_INET, NULL, net, len)); + memput(ansbuf, MAXPACKET); + return (result); +} + +static struct nwent * +get1101answer(struct irs_nw *this, + u_char *ansbuf, int anslen, enum by_what by_what, + int af, const char *name, const u_char *addr, int addrlen) +{ + struct pvt *pvt = (struct pvt *)this->private; + int type, class, ancount, qdcount, haveanswer; + char *bp, *ep, **ap; + u_char *cp, *eom; + HEADER *hp; + + /* Initialize, and parse header. */ + eom = ansbuf + anslen; + if (ansbuf + HFIXEDSZ > eom) { + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); + return (NULL); + } + hp = (HEADER *)ansbuf; + cp = ansbuf + HFIXEDSZ; + qdcount = ntohs(hp->qdcount); + while (qdcount-- > 0) { + int n = dn_skipname(cp, eom); + cp += n + QFIXEDSZ; + if (n < 0 || cp > eom) { + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); + return (NULL); + } + } + ancount = ntohs(hp->ancount); + if (!ancount) { + if (hp->aa) + RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); + else + RES_SET_H_ERRNO(pvt->res, TRY_AGAIN); + return (NULL); + } + + /* Prepare a return structure. */ + bp = pvt->buf; + ep = pvt->buf + sizeof(pvt->buf); + pvt->net.n_name = NULL; + pvt->net.n_aliases = pvt->ali; + pvt->net.n_addrtype = af; + pvt->net.n_addr = NULL; + pvt->net.n_length = addrlen; + + /* Save input key if given. */ + switch (by_what) { + case by_name: + if (name != NULL) { + int n = strlen(name) + 1; + + if (n > (ep - bp)) { + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); + return (NULL); + } + pvt->net.n_name = strcpy(bp, name); /* (checked) */ + bp += n; + } + break; + case by_addr: + if (addr != NULL && addrlen != 0) { + int n = addrlen / 8 + ((addrlen % 8) != 0); + + if (INADDRSZ > (ep - bp)) { + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); + return (NULL); + } + memset(bp, 0, INADDRSZ); + memcpy(bp, addr, n); + pvt->net.n_addr = bp; + bp += INADDRSZ; + } + break; + default: + abort(); + } + + /* Parse the answer, collect aliases. */ + ap = pvt->ali; + haveanswer = 0; + while (--ancount >= 0 && cp < eom) { + int n = dn_expand(ansbuf, eom, cp, bp, ep - bp); + + cp += n; /*%< Owner */ + if (n < 0 || !maybe_dnok(pvt->res, bp) || + cp + 3 * INT16SZ + INT32SZ > eom) { + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); + return (NULL); + } + GETSHORT(type, cp); /*%< Type */ + GETSHORT(class, cp); /*%< Class */ + cp += INT32SZ; /*%< TTL */ + GETSHORT(n, cp); /*%< RDLENGTH */ + if (class == C_IN && type == T_PTR) { + int nn; + + nn = dn_expand(ansbuf, eom, cp, bp, ep - bp); + if (nn < 0 || !maybe_hnok(pvt->res, bp) || nn != n) { + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); + return (NULL); + } + normalize_name(bp); + switch (by_what) { + case by_addr: { + if (pvt->net.n_name == NULL) + pvt->net.n_name = bp; + else if (ns_samename(pvt->net.n_name, bp) == 1) + break; + else + *ap++ = bp; + nn = strlen(bp) + 1; + bp += nn; + haveanswer++; + break; + } + case by_name: { + u_int b1, b2, b3, b4; + + if (pvt->net.n_addr != NULL || + sscanf(bp, "%u.%u.%u.%u.in-addr.arpa", + &b1, &b2, &b3, &b4) != 4) + break; + if ((ep - bp) < INADDRSZ) { + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); + return (NULL); + } + pvt->net.n_addr = bp; + *bp++ = b4; + *bp++ = b3; + *bp++ = b2; + *bp++ = b1; + pvt->net.n_length = INADDRSZ * 8; + haveanswer++; + } + } + } + cp += n; /*%< RDATA */ + } + if (!haveanswer) { + RES_SET_H_ERRNO(pvt->res, TRY_AGAIN); + return (NULL); + } + *ap = NULL; + + return (&pvt->net); +} + +static struct nwent * +get1101mask(struct irs_nw *this, struct nwent *nwent) { + struct pvt *pvt = (struct pvt *)this->private; + char qbuf[sizeof "255.255.255.255.in-addr.arpa"], owner[MAXDNAME]; + int anslen, type, class, ancount, qdcount; + u_char *ansbuf, *cp, *eom; + HEADER *hp; + + if (!nwent) + return (NULL); + if (make1101inaddr(nwent->n_addr, nwent->n_length, qbuf, sizeof qbuf) + < 0) { + /* "First, do no harm." */ + return (nwent); + } + + ansbuf = memget(MAXPACKET); + if (ansbuf == NULL) { + errno = ENOMEM; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + return (NULL); + } + /* Query for the A RR that would hold this network's mask. */ + anslen = res_nquery(pvt->res, qbuf, C_IN, T_A, ansbuf, MAXPACKET); + if (anslen < HFIXEDSZ) { + memput(ansbuf, MAXPACKET); + return (nwent); + } + + /* Initialize, and parse header. */ + hp = (HEADER *)ansbuf; + cp = ansbuf + HFIXEDSZ; + eom = ansbuf + anslen; + qdcount = ntohs(hp->qdcount); + while (qdcount-- > 0) { + int n = dn_skipname(cp, eom); + cp += n + QFIXEDSZ; + if (n < 0 || cp > eom) { + memput(ansbuf, MAXPACKET); + return (nwent); + } + } + ancount = ntohs(hp->ancount); + + /* Parse the answer, collect aliases. */ + while (--ancount >= 0 && cp < eom) { + int n = dn_expand(ansbuf, eom, cp, owner, sizeof owner); + + if (n < 0 || !maybe_dnok(pvt->res, owner)) + break; + cp += n; /*%< Owner */ + if (cp + 3 * INT16SZ + INT32SZ > eom) + break; + GETSHORT(type, cp); /*%< Type */ + GETSHORT(class, cp); /*%< Class */ + cp += INT32SZ; /*%< TTL */ + GETSHORT(n, cp); /*%< RDLENGTH */ + if (cp + n > eom) + break; + if (n == INADDRSZ && class == C_IN && type == T_A && + ns_samename(qbuf, owner) == 1) { + /* This A RR indicates the actual netmask. */ + int nn, mm; + + nwent->n_length = 0; + for (nn = 0; nn < INADDRSZ; nn++) + for (mm = 7; mm >= 0; mm--) + if (cp[nn] & (1 << mm)) + nwent->n_length++; + else + break; + } + cp += n; /*%< RDATA */ + } + memput(ansbuf, MAXPACKET); + return (nwent); +} + +static int +make1101inaddr(const u_char *net, int bits, char *name, int size) { + int n, m; + char *ep; + + ep = name + size; + + /* Zero fill any whole bytes left out of the prefix. */ + for (n = (32 - bits) / 8; n > 0; n--) { + if (ep - name < (int)(sizeof "0.")) + goto emsgsize; + m = SPRINTF((name, "0.")); + name += m; + } + + /* Format the partial byte, if any, within the prefix. */ + if ((n = bits % 8) != 0) { + if (ep - name < (int)(sizeof "255.")) + goto emsgsize; + m = SPRINTF((name, "%u.", + net[bits / 8] & ~((1 << (8 - n)) - 1))); + name += m; + } + + /* Format the whole bytes within the prefix. */ + for (n = bits / 8; n > 0; n--) { + if (ep - name < (int)(sizeof "255.")) + goto emsgsize; + m = SPRINTF((name, "%u.", net[n - 1])); + name += m; + } + + /* Add the static text. */ + if (ep - name < (int)(sizeof "in-addr.arpa")) + goto emsgsize; + (void) SPRINTF((name, "in-addr.arpa")); + return (0); + + emsgsize: + errno = EMSGSIZE; + return (-1); +} + +static void +normalize_name(char *name) { + char *t; + + /* Make lower case. */ + for (t = name; *t; t++) + if (isascii((unsigned char)*t) && isupper((unsigned char)*t)) + *t = tolower((*t)&0xff); + + /* Remove trailing dots. */ + while (t > name && t[-1] == '.') + *--t = '\0'; +} + +static int +init(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->res && !nw_res_get(this)) + return (-1); + if (((pvt->res->options & RES_INIT) == 0U) && + res_ninit(pvt->res) == -1) + return (-1); + return (0); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/dns_p.h b/contrib/bind-9.5.2/lib/bind/irs/dns_p.h new file mode 100644 index 0000000000..d85ae2a238 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/dns_p.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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: dns_p.h,v 1.4 2005/04/27 04:56:22 sra Exp $ + */ + +#ifndef _DNS_P_H_INCLUDED +#define _DNS_P_H_INCLUDED + +#define maybe_ok(res, nm, ok) (((res)->options & RES_NOCHECKNAME) != 0U || \ + (ok)(nm) != 0) +#define maybe_hnok(res, hn) maybe_ok((res), (hn), res_hnok) +#define maybe_dnok(res, dn) maybe_ok((res), (dn), res_dnok) + +/*% + * Object state. + */ +struct dns_p { + void *hes_ctx; + struct __res_state *res; + void (*free_res) __P((void *)); +}; + +/* + * Methods. + */ + +extern struct irs_gr * irs_dns_gr __P((struct irs_acc *)); +extern struct irs_pw * irs_dns_pw __P((struct irs_acc *)); +extern struct irs_sv * irs_dns_sv __P((struct irs_acc *)); +extern struct irs_pr * irs_dns_pr __P((struct irs_acc *)); +extern struct irs_ho * irs_dns_ho __P((struct irs_acc *)); +extern struct irs_nw * irs_dns_nw __P((struct irs_acc *)); + +#endif /*_DNS_P_H_INCLUDED*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/dns_pr.c b/contrib/bind-9.5.2/lib/bind/irs/dns_pr.c new file mode 100644 index 0000000000..137f306218 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/dns_pr.c @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: dns_pr.c,v 1.5 2005/04/27 04:56:22 sra Exp $"; +#endif + +/* Imports */ + +#include "port_before.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "hesiod.h" +#include "dns_p.h" + +/* Types. */ + +struct pvt { + struct dns_p * dns; + struct protoent proto; + char * prbuf; +}; + +/* Forward. */ + +static void pr_close(struct irs_pr *); +static struct protoent * pr_byname(struct irs_pr *, const char *); +static struct protoent * pr_bynumber(struct irs_pr *, int); +static struct protoent * pr_next(struct irs_pr *); +static void pr_rewind(struct irs_pr *); +static void pr_minimize(struct irs_pr *); +static struct __res_state * pr_res_get(struct irs_pr *); +static void pr_res_set(struct irs_pr *, + struct __res_state *, + void (*)(void *)); + +static struct protoent * parse_hes_list(struct irs_pr *, char **); + +/* Public. */ + +struct irs_pr * +irs_dns_pr(struct irs_acc *this) { + struct dns_p *dns = (struct dns_p *)this->private; + struct pvt *pvt; + struct irs_pr *pr; + + if (!dns->hes_ctx) { + errno = ENODEV; + return (NULL); + } + if (!(pvt = memget(sizeof *pvt))) { + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + if (!(pr = memget(sizeof *pr))) { + memput(pvt, sizeof *pvt); + errno = ENOMEM; + return (NULL); + } + memset(pr, 0x5e, sizeof *pr); + pvt->dns = dns; + pr->private = pvt; + pr->byname = pr_byname; + pr->bynumber = pr_bynumber; + pr->next = pr_next; + pr->rewind = pr_rewind; + pr->close = pr_close; + pr->minimize = pr_minimize; + pr->res_get = pr_res_get; + pr->res_set = pr_res_set; + return (pr); +} + +/* Methods. */ + +static void +pr_close(struct irs_pr *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->proto.p_aliases) + free(pvt->proto.p_aliases); + if (pvt->prbuf) + free(pvt->prbuf); + + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct protoent * +pr_byname(struct irs_pr *this, const char *name) { + struct pvt *pvt = (struct pvt *)this->private; + struct dns_p *dns = pvt->dns; + struct protoent *proto; + char **hes_list; + + if (!(hes_list = hesiod_resolve(dns->hes_ctx, name, "protocol"))) + return (NULL); + + proto = parse_hes_list(this, hes_list); + hesiod_free_list(dns->hes_ctx, hes_list); + return (proto); +} + +static struct protoent * +pr_bynumber(struct irs_pr *this, int num) { + struct pvt *pvt = (struct pvt *)this->private; + struct dns_p *dns = pvt->dns; + struct protoent *proto; + char numstr[16]; + char **hes_list; + + sprintf(numstr, "%d", num); + if (!(hes_list = hesiod_resolve(dns->hes_ctx, numstr, "protonum"))) + return (NULL); + + proto = parse_hes_list(this, hes_list); + hesiod_free_list(dns->hes_ctx, hes_list); + return (proto); +} + +static struct protoent * +pr_next(struct irs_pr *this) { + UNUSED(this); + errno = ENODEV; + return (NULL); +} + +static void +pr_rewind(struct irs_pr *this) { + UNUSED(this); + /* NOOP */ +} + +static void +pr_minimize(struct irs_pr *this) { + UNUSED(this); + /* NOOP */ +} + +static struct __res_state * +pr_res_get(struct irs_pr *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct dns_p *dns = pvt->dns; + + return (__hesiod_res_get(dns->hes_ctx)); +} + +static void +pr_res_set(struct irs_pr *this, struct __res_state * res, + void (*free_res)(void *)) { + struct pvt *pvt = (struct pvt *)this->private; + struct dns_p *dns = pvt->dns; + + __hesiod_res_set(dns->hes_ctx, res, free_res); +} + +/* Private. */ + +static struct protoent * +parse_hes_list(struct irs_pr *this, char **hes_list) { + struct pvt *pvt = (struct pvt *)this->private; + char *p, *cp, **cpp, **new; + int num = 0; + int max = 0; + + for (cpp = hes_list; *cpp; cpp++) { + cp = *cpp; + + /* Strip away comments, if any. */ + if ((p = strchr(cp, '#'))) + *p = 0; + + /* Skip blank lines. */ + p = cp; + while (*p && !isspace((unsigned char)*p)) + p++; + if (!*p) + continue; + + /* OK, we've got a live one. Let's parse it for real. */ + if (pvt->prbuf) + free(pvt->prbuf); + pvt->prbuf = strdup(cp); + + p = pvt->prbuf; + pvt->proto.p_name = p; + while (*p && !isspace((unsigned char)*p)) + p++; + if (!*p) + continue; + *p++ = '\0'; + + pvt->proto.p_proto = atoi(p); + while (*p && !isspace((unsigned char)*p)) + p++; + if (*p) + *p++ = '\0'; + + while (*p) { + if ((num + 1) >= max || !pvt->proto.p_aliases) { + max += 10; + new = realloc(pvt->proto.p_aliases, + max * sizeof(char *)); + if (!new) { + errno = ENOMEM; + goto cleanup; + } + pvt->proto.p_aliases = new; + } + pvt->proto.p_aliases[num++] = p; + while (*p && !isspace((unsigned char)*p)) + p++; + if (*p) + *p++ = '\0'; + } + if (!pvt->proto.p_aliases) + pvt->proto.p_aliases = malloc(sizeof(char *)); + if (!pvt->proto.p_aliases) + goto cleanup; + pvt->proto.p_aliases[num] = NULL; + return (&pvt->proto); + } + + cleanup: + if (pvt->proto.p_aliases) { + free(pvt->proto.p_aliases); + pvt->proto.p_aliases = NULL; + } + if (pvt->prbuf) { + free(pvt->prbuf); + pvt->prbuf = NULL; + } + return (NULL); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/dns_pw.c b/contrib/bind-9.5.2/lib/bind/irs/dns_pw.c new file mode 100644 index 0000000000..4ea97adfdb --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/dns_pw.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: dns_pw.c,v 1.3 2005/04/27 04:56:22 sra Exp $"; +#endif + +#include "port_before.h" + +#ifndef WANT_IRS_PW +static int __bind_irs_pw_unneeded; +#else + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "hesiod.h" +#include "dns_p.h" + +/* Types. */ + +struct pvt { + struct dns_p * dns; + struct passwd passwd; + char * pwbuf; +}; + +/* Forward. */ + +static void pw_close(struct irs_pw *); +static struct passwd * pw_byname(struct irs_pw *, const char *); +static struct passwd * pw_byuid(struct irs_pw *, uid_t); +static struct passwd * pw_next(struct irs_pw *); +static void pw_rewind(struct irs_pw *); +static void pw_minimize(struct irs_pw *); +static struct __res_state * pw_res_get(struct irs_pw *); +static void pw_res_set(struct irs_pw *, + struct __res_state *, + void (*)(void *)); + +static struct passwd * getpwcommon(struct irs_pw *, const char *, + const char *); + +/* Public. */ + +struct irs_pw * +irs_dns_pw(struct irs_acc *this) { + struct dns_p *dns = (struct dns_p *)this->private; + struct irs_pw *pw; + struct pvt *pvt; + + if (!dns || !dns->hes_ctx) { + errno = ENODEV; + return (NULL); + } + if (!(pvt = memget(sizeof *pvt))) { + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + pvt->dns = dns; + if (!(pw = memget(sizeof *pw))) { + memput(pvt, sizeof *pvt); + errno = ENOMEM; + return (NULL); + } + memset(pw, 0x5e, sizeof *pw); + pw->private = pvt; + pw->close = pw_close; + pw->byname = pw_byname; + pw->byuid = pw_byuid; + pw->next = pw_next; + pw->rewind = pw_rewind; + pw->minimize = pw_minimize; + pw->res_get = pw_res_get; + pw->res_set = pw_res_set; + return (pw); +} + +/* Methods. */ + +static void +pw_close(struct irs_pw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->pwbuf) + free(pvt->pwbuf); + + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct passwd * +pw_byname(struct irs_pw *this, const char *nam) { + return (getpwcommon(this, nam, "passwd")); +} + +static struct passwd * +pw_byuid(struct irs_pw *this, uid_t uid) { + char uidstr[16]; + + sprintf(uidstr, "%lu", (u_long)uid); + return (getpwcommon(this, uidstr, "uid")); +} + +static struct passwd * +pw_next(struct irs_pw *this) { + UNUSED(this); + errno = ENODEV; + return (NULL); +} + +static void +pw_rewind(struct irs_pw *this) { + UNUSED(this); + /* NOOP */ +} + +static void +pw_minimize(struct irs_pw *this) { + UNUSED(this); + /* NOOP */ +} + +static struct __res_state * +pw_res_get(struct irs_pw *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct dns_p *dns = pvt->dns; + + return (__hesiod_res_get(dns->hes_ctx)); +} + +static void +pw_res_set(struct irs_pw *this, struct __res_state * res, + void (*free_res)(void *)) { + struct pvt *pvt = (struct pvt *)this->private; + struct dns_p *dns = pvt->dns; + + __hesiod_res_set(dns->hes_ctx, res, free_res); +} + +/* Private. */ + +static struct passwd * +getpwcommon(struct irs_pw *this, const char *arg, const char *type) { + struct pvt *pvt = (struct pvt *)this->private; + char **hes_list, *cp; + + if (!(hes_list = hesiod_resolve(pvt->dns->hes_ctx, arg, type))) + return (NULL); + if (!*hes_list) { + hesiod_free_list(pvt->dns->hes_ctx, hes_list); + errno = ENOENT; + return (NULL); + } + + memset(&pvt->passwd, 0, sizeof pvt->passwd); + if (pvt->pwbuf) + free(pvt->pwbuf); + pvt->pwbuf = strdup(*hes_list); + hesiod_free_list(pvt->dns->hes_ctx, hes_list); + + cp = pvt->pwbuf; + pvt->passwd.pw_name = cp; + if (!(cp = strchr(cp, ':'))) + goto cleanup; + *cp++ = '\0'; + + pvt->passwd.pw_passwd = cp; + if (!(cp = strchr(cp, ':'))) + goto cleanup; + *cp++ = '\0'; + + pvt->passwd.pw_uid = atoi(cp); + if (!(cp = strchr(cp, ':'))) + goto cleanup; + *cp++ = '\0'; + + pvt->passwd.pw_gid = atoi(cp); + if (!(cp = strchr(cp, ':'))) + goto cleanup; + *cp++ = '\0'; + + pvt->passwd.pw_gecos = cp; + if (!(cp = strchr(cp, ':'))) + goto cleanup; + *cp++ = '\0'; + + pvt->passwd.pw_dir = cp; + if (!(cp = strchr(cp, ':'))) + goto cleanup; + *cp++ = '\0'; + + pvt->passwd.pw_shell = cp; + return (&pvt->passwd); + + cleanup: + free(pvt->pwbuf); + pvt->pwbuf = NULL; + return (NULL); +} + +#endif /* WANT_IRS_PW */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/dns_sv.c b/contrib/bind-9.5.2/lib/bind/irs/dns_sv.c new file mode 100644 index 0000000000..c3294255b8 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/dns_sv.c @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: dns_sv.c,v 1.5 2005/04/27 04:56:23 sra Exp $"; +#endif + +/* Imports */ + +#include "port_before.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "hesiod.h" +#include "dns_p.h" + +/* Definitions */ + +struct pvt { + struct dns_p * dns; + struct servent serv; + char * svbuf; + struct __res_state * res; + void (*free_res)(void *); +}; + +/* Forward. */ + +static void sv_close(struct irs_sv *); +static struct servent * sv_byname(struct irs_sv *, + const char *, const char *); +static struct servent * sv_byport(struct irs_sv *, int, const char *); +static struct servent * sv_next(struct irs_sv *); +static void sv_rewind(struct irs_sv *); +static void sv_minimize(struct irs_sv *); +#ifdef SV_RES_SETGET +static struct __res_state * sv_res_get(struct irs_sv *); +static void sv_res_set(struct irs_sv *, + struct __res_state *, + void (*)(void *)); +#endif + +static struct servent * parse_hes_list(struct irs_sv *, + char **, const char *); + +/* Public */ + +struct irs_sv * +irs_dns_sv(struct irs_acc *this) { + struct dns_p *dns = (struct dns_p *)this->private; + struct irs_sv *sv; + struct pvt *pvt; + + if (!dns || !dns->hes_ctx) { + errno = ENODEV; + return (NULL); + } + if (!(pvt = memget(sizeof *pvt))) { + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + pvt->dns = dns; + if (!(sv = memget(sizeof *sv))) { + memput(pvt, sizeof *pvt); + errno = ENOMEM; + return (NULL); + } + memset(sv, 0x5e, sizeof *sv); + sv->private = pvt; + sv->byname = sv_byname; + sv->byport = sv_byport; + sv->next = sv_next; + sv->rewind = sv_rewind; + sv->close = sv_close; + sv->minimize = sv_minimize; +#ifdef SV_RES_SETGET + sv->res_get = sv_res_get; + sv->res_set = sv_res_set; +#else + sv->res_get = NULL; /*%< sv_res_get; */ + sv->res_set = NULL; /*%< sv_res_set; */ +#endif + return (sv); +} + +/* Methods */ + +static void +sv_close(struct irs_sv *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->serv.s_aliases) + free(pvt->serv.s_aliases); + if (pvt->svbuf) + free(pvt->svbuf); + + if (pvt->res && pvt->free_res) + (*pvt->free_res)(pvt->res); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct servent * +sv_byname(struct irs_sv *this, const char *name, const char *proto) { + struct pvt *pvt = (struct pvt *)this->private; + struct dns_p *dns = pvt->dns; + struct servent *s; + char **hes_list; + + if (!(hes_list = hesiod_resolve(dns->hes_ctx, name, "service"))) + return (NULL); + + s = parse_hes_list(this, hes_list, proto); + hesiod_free_list(dns->hes_ctx, hes_list); + return (s); +} + +static struct servent * +sv_byport(struct irs_sv *this, int port, const char *proto) { + struct pvt *pvt = (struct pvt *)this->private; + struct dns_p *dns = pvt->dns; + struct servent *s; + char portstr[16]; + char **hes_list; + + sprintf(portstr, "%d", ntohs(port)); + if (!(hes_list = hesiod_resolve(dns->hes_ctx, portstr, "port"))) + return (NULL); + + s = parse_hes_list(this, hes_list, proto); + hesiod_free_list(dns->hes_ctx, hes_list); + return (s); +} + +static struct servent * +sv_next(struct irs_sv *this) { + UNUSED(this); + errno = ENODEV; + return (NULL); +} + +static void +sv_rewind(struct irs_sv *this) { + UNUSED(this); + /* NOOP */ +} + +/* Private */ + +static struct servent * +parse_hes_list(struct irs_sv *this, char **hes_list, const char *proto) { + struct pvt *pvt = (struct pvt *)this->private; + char *p, *cp, **cpp, **new; + int proto_len; + int num = 0; + int max = 0; + + for (cpp = hes_list; *cpp; cpp++) { + cp = *cpp; + + /* Strip away comments, if any. */ + if ((p = strchr(cp, '#'))) + *p = 0; + + /* Check to make sure the protocol matches. */ + p = cp; + while (*p && !isspace((unsigned char)*p)) + p++; + if (!*p) + continue; + if (proto) { + proto_len = strlen(proto); + if (strncasecmp(++p, proto, proto_len) != 0) + continue; + if (p[proto_len] && !isspace(p[proto_len]&0xff)) + continue; + } + /* OK, we've got a live one. Let's parse it for real. */ + if (pvt->svbuf) + free(pvt->svbuf); + pvt->svbuf = strdup(cp); + + p = pvt->svbuf; + pvt->serv.s_name = p; + while (*p && !isspace(*p&0xff)) + p++; + if (!*p) + continue; + *p++ = '\0'; + + pvt->serv.s_proto = p; + while (*p && !isspace(*p&0xff)) + p++; + if (!*p) + continue; + *p++ = '\0'; + + pvt->serv.s_port = htons((u_short) atoi(p)); + while (*p && !isspace(*p&0xff)) + p++; + if (*p) + *p++ = '\0'; + + while (*p) { + if ((num + 1) >= max || !pvt->serv.s_aliases) { + max += 10; + new = realloc(pvt->serv.s_aliases, + max * sizeof(char *)); + if (!new) { + errno = ENOMEM; + goto cleanup; + } + pvt->serv.s_aliases = new; + } + pvt->serv.s_aliases[num++] = p; + while (*p && !isspace(*p&0xff)) + p++; + if (*p) + *p++ = '\0'; + } + if (!pvt->serv.s_aliases) + pvt->serv.s_aliases = malloc(sizeof(char *)); + if (!pvt->serv.s_aliases) + goto cleanup; + pvt->serv.s_aliases[num] = NULL; + return (&pvt->serv); + } + + cleanup: + if (pvt->serv.s_aliases) { + free(pvt->serv.s_aliases); + pvt->serv.s_aliases = NULL; + } + if (pvt->svbuf) { + free(pvt->svbuf); + pvt->svbuf = NULL; + } + return (NULL); +} + +static void +sv_minimize(struct irs_sv *this) { + UNUSED(this); + /* NOOP */ +} + +#ifdef SV_RES_SETGET +static struct __res_state * +sv_res_get(struct irs_sv *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct dns_p *dns = pvt->dns; + + return (__hesiod_res_get(dns->hes_ctx)); +} + +static void +sv_res_set(struct irs_sv *this, struct __res_state * res, + void (*free_res)(void *)) { + struct pvt *pvt = (struct pvt *)this->private; + struct dns_p *dns = pvt->dns; + + __hesiod_res_set(dns->hes_ctx, res, free_res); +} +#endif + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/gai_strerror.c b/contrib/bind-9.5.2/lib/bind/irs/gai_strerror.c new file mode 100644 index 0000000000..9ca1c4bfe1 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/gai_strerror.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 2001 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#include +#include +#include + +#ifdef DO_PTHREADS +#include +#include +#endif + +static const char *gai_errlist[] = { + "no error", + "address family not supported for name",/*%< EAI_ADDRFAMILY */ + "temporary failure", /*%< EAI_AGAIN */ + "invalid flags", /*%< EAI_BADFLAGS */ + "permanent failure", /*%< EAI_FAIL */ + "address family not supported", /*%< EAI_FAMILY */ + "memory failure", /*%< EAI_MEMORY */ + "no address", /*%< EAI_NODATA */ + "unknown name or service", /*%< EAI_NONAME */ + "service not supported for socktype", /*%< EAI_SERVICE */ + "socktype not supported", /*%< EAI_SOCKTYPE */ + "system failure", /*%< EAI_SYSTEM */ + "bad hints", /*%< EAI_BADHINTS */ + "bad protocol", /*%< EAI_PROTOCOL */ + "unknown error" /*%< Must be last. */ +}; + +static const int gai_nerr = (sizeof(gai_errlist)/sizeof(*gai_errlist)); + +#define EAI_BUFSIZE 128 + +const char * +gai_strerror(int ecode) { +#ifndef DO_PTHREADS + static char buf[EAI_BUFSIZE]; +#else /* DO_PTHREADS */ +#ifndef LIBBIND_MUTEX_INITIALIZER +#define LIBBIND_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +#endif + static pthread_mutex_t lock = LIBBIND_MUTEX_INITIALIZER; + static pthread_key_t key; + static int once = 0; + char *buf; +#endif + + if (ecode >= 0 && ecode < (gai_nerr - 1)) + return (gai_errlist[ecode]); + +#ifdef DO_PTHREADS + if (!once) { + if (pthread_mutex_lock(&lock) != 0) + goto unknown; + if (!once) { + if (pthread_key_create(&key, free) != 0) { + (void)pthread_mutex_unlock(&lock); + goto unknown; + } + once = 1; + } + if (pthread_mutex_unlock(&lock) != 0) + goto unknown; + } + + buf = pthread_getspecific(key); + if (buf == NULL) { + buf = malloc(EAI_BUFSIZE); + if (buf == NULL) + goto unknown; + if (pthread_setspecific(key, buf) != 0) { + free(buf); + goto unknown; + } + } +#endif + /* + * XXX This really should be snprintf(buf, EAI_BUFSIZE, ...). + * It is safe until message catalogs are used. + */ + sprintf(buf, "%s: %d", gai_errlist[gai_nerr - 1], ecode); + return (buf); + +#ifdef DO_PTHREADS + unknown: + return ("unknown error"); +#endif +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/gen.c b/contrib/bind-9.5.2/lib/bind/irs/gen.c new file mode 100644 index 0000000000..04105b3025 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/gen.c @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: gen.c,v 1.7 2005/04/27 04:56:23 sra Exp $"; +#endif + +/*! \file + * \brief + * this is the top level dispatcher + * + * The dispatcher is implemented as an accessor class; it is an + * accessor class that calls other accessor classes, as controlled by a + * configuration file. + * + * A big difference between this accessor class and others is that the + * map class initializers are NULL, and the map classes are already + * filled in with method functions that will do the right thing. + */ + +/* Imports */ + +#include "port_before.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "gen_p.h" + +/* Definitions */ + +struct nameval { + const char * name; + int val; +}; + +static const struct nameval acc_names[irs_nacc+1] = { + { "local", irs_lcl }, + { "dns", irs_dns }, + { "nis", irs_nis }, + { "irp", irs_irp }, + { NULL, irs_nacc } +}; + +typedef struct irs_acc *(*accinit) __P((const char *options)); + +static const accinit accs[irs_nacc+1] = { + irs_lcl_acc, + irs_dns_acc, +#ifdef WANT_IRS_NIS + irs_nis_acc, +#else + NULL, +#endif + irs_irp_acc, + NULL +}; + +static const struct nameval map_names[irs_nmap+1] = { + { "group", irs_gr }, + { "passwd", irs_pw }, + { "services", irs_sv }, + { "protocols", irs_pr }, + { "hosts", irs_ho }, + { "networks", irs_nw }, + { "netgroup", irs_ng }, + { NULL, irs_nmap } +}; + +static const struct nameval option_names[] = { + { "merge", IRS_MERGE }, + { "continue", IRS_CONTINUE }, + { NULL, 0 } +}; + +/* Forward */ + +static void gen_close(struct irs_acc *); +static struct __res_state * gen_res_get(struct irs_acc *); +static void gen_res_set(struct irs_acc *, struct __res_state *, + void (*)(void *)); +static int find_name(const char *, const struct nameval nv[]); +static void init_map_rules(struct gen_p *, const char *conf_file); +static struct irs_rule *release_rule(struct irs_rule *); +static int add_rule(struct gen_p *, + enum irs_map_id, enum irs_acc_id, + const char *); + +/* Public */ + +struct irs_acc * +irs_gen_acc(const char *options, const char *conf_file) { + struct irs_acc *acc; + struct gen_p *irs; + + if (!(acc = memget(sizeof *acc))) { + errno = ENOMEM; + return (NULL); + } + memset(acc, 0x5e, sizeof *acc); + if (!(irs = memget(sizeof *irs))) { + errno = ENOMEM; + memput(acc, sizeof *acc); + return (NULL); + } + memset(irs, 0x5e, sizeof *irs); + irs->options = strdup(options); + irs->res = NULL; + irs->free_res = NULL; + memset(irs->accessors, 0, sizeof irs->accessors); + memset(irs->map_rules, 0, sizeof irs->map_rules); + init_map_rules(irs, conf_file); + acc->private = irs; +#ifdef WANT_IRS_GR + acc->gr_map = irs_gen_gr; +#else + acc->gr_map = NULL; +#endif +#ifdef WANT_IRS_PW + acc->pw_map = irs_gen_pw; +#else + acc->pw_map = NULL; +#endif + acc->sv_map = irs_gen_sv; + acc->pr_map = irs_gen_pr; + acc->ho_map = irs_gen_ho; + acc->nw_map = irs_gen_nw; + acc->ng_map = irs_gen_ng; + acc->res_get = gen_res_get; + acc->res_set = gen_res_set; + acc->close = gen_close; + return (acc); +} + +/* Methods */ + +static struct __res_state * +gen_res_get(struct irs_acc *this) { + struct gen_p *irs = (struct gen_p *)this->private; + + if (irs->res == NULL) { + struct __res_state *res; + res = (struct __res_state *)malloc(sizeof *res); + if (res == NULL) + return (NULL); + memset(res, 0, sizeof *res); + gen_res_set(this, res, free); + } + + if (((irs->res->options & RES_INIT) == 0U) && res_ninit(irs->res) < 0) + return (NULL); + + return (irs->res); +} + +static void +gen_res_set(struct irs_acc *this, struct __res_state *res, + void (*free_res)(void *)) { + struct gen_p *irs = (struct gen_p *)this->private; +#if 0 + struct irs_rule *rule; + struct irs_ho *ho; + struct irs_nw *nw; +#endif + + if (irs->res && irs->free_res) { + res_nclose(irs->res); + (*irs->free_res)(irs->res); + } + + irs->res = res; + irs->free_res = free_res; + +#if 0 + for (rule = irs->map_rules[irs_ho]; rule; rule = rule->next) { + ho = rule->inst->ho; + + (*ho->res_set)(ho, res, NULL); + } + for (rule = irs->map_rules[irs_nw]; rule; rule = rule->next) { + nw = rule->inst->nw; + + (*nw->res_set)(nw, res, NULL); + } +#endif +} + +static void +gen_close(struct irs_acc *this) { + struct gen_p *irs = (struct gen_p *)this->private; + int n; + + /* Search rules. */ + for (n = 0; n < irs_nmap; n++) + while (irs->map_rules[n] != NULL) + irs->map_rules[n] = release_rule(irs->map_rules[n]); + + /* Access methods. */ + for (n = 0; n < irs_nacc; n++) { + /* Map objects. */ + if (irs->accessors[n].gr != NULL) + (*irs->accessors[n].gr->close)(irs->accessors[n].gr); + if (irs->accessors[n].pw != NULL) + (*irs->accessors[n].pw->close)(irs->accessors[n].pw); + if (irs->accessors[n].sv != NULL) + (*irs->accessors[n].sv->close)(irs->accessors[n].sv); + if (irs->accessors[n].pr != NULL) + (*irs->accessors[n].pr->close)(irs->accessors[n].pr); + if (irs->accessors[n].ho != NULL) + (*irs->accessors[n].ho->close)(irs->accessors[n].ho); + if (irs->accessors[n].nw != NULL) + (*irs->accessors[n].nw->close)(irs->accessors[n].nw); + if (irs->accessors[n].ng != NULL) + (*irs->accessors[n].ng->close)(irs->accessors[n].ng); + /* Enclosing accessor. */ + if (irs->accessors[n].acc != NULL) + (*irs->accessors[n].acc->close)(irs->accessors[n].acc); + } + + /* The options string was strdup'd. */ + free((void*)irs->options); + + if (irs->res && irs->free_res) + (*irs->free_res)(irs->res); + + /* The private data container. */ + memput(irs, sizeof *irs); + + /* The object. */ + memput(this, sizeof *this); +} + +/* Private */ + +static int +find_name(const char *name, const struct nameval names[]) { + int n; + + for (n = 0; names[n].name != NULL; n++) + if (strcmp(name, names[n].name) == 0) + return (names[n].val); + return (-1); +} + +static struct irs_rule * +release_rule(struct irs_rule *rule) { + struct irs_rule *next = rule->next; + + memput(rule, sizeof *rule); + return (next); +} + +static int +add_rule(struct gen_p *irs, + enum irs_map_id map, enum irs_acc_id acc, + const char *options) +{ + struct irs_rule **rules, *last, *tmp, *new; + struct irs_inst *inst; + const char *cp; + int n; + +#ifndef WANT_IRS_GR + if (map == irs_gr) + return (-1); +#endif +#ifndef WANT_IRS_PW + if (map == irs_pw) + return (-1); +#endif +#ifndef WANT_IRS_NIS + if (acc == irs_nis) + return (-1); +#endif + new = memget(sizeof *new); + if (new == NULL) + return (-1); + memset(new, 0x5e, sizeof *new); + new->next = NULL; + + new->inst = &irs->accessors[acc]; + + new->flags = 0; + cp = options; + while (cp && *cp) { + char option[50], *next; + + next = strchr(cp, ','); + if (next) + n = next++ - cp; + else + n = strlen(cp); + if ((size_t)n > sizeof option - 1) + n = sizeof option - 1; + strncpy(option, cp, n); + option[n] = '\0'; + + n = find_name(option, option_names); + if (n >= 0) + new->flags |= n; + + cp = next; + } + + rules = &irs->map_rules[map]; + for (last = NULL, tmp = *rules; + tmp != NULL; + last = tmp, tmp = tmp->next) + (void)NULL; + if (last == NULL) + *rules = new; + else + last->next = new; + + /* Try to instantiate map accessors for this if necessary & approp. */ + inst = &irs->accessors[acc]; + if (inst->acc == NULL && accs[acc] != NULL) + inst->acc = (*accs[acc])(irs->options); + if (inst->acc != NULL) { + if (inst->gr == NULL && inst->acc->gr_map != NULL) + inst->gr = (*inst->acc->gr_map)(inst->acc); + if (inst->pw == NULL && inst->acc->pw_map != NULL) + inst->pw = (*inst->acc->pw_map)(inst->acc); + if (inst->sv == NULL && inst->acc->sv_map != NULL) + inst->sv = (*inst->acc->sv_map)(inst->acc); + if (inst->pr == NULL && inst->acc->pr_map != NULL) + inst->pr = (*inst->acc->pr_map)(inst->acc); + if (inst->ho == NULL && inst->acc->ho_map != NULL) + inst->ho = (*inst->acc->ho_map)(inst->acc); + if (inst->nw == NULL && inst->acc->nw_map != NULL) + inst->nw = (*inst->acc->nw_map)(inst->acc); + if (inst->ng == NULL && inst->acc->ng_map != NULL) + inst->ng = (*inst->acc->ng_map)(inst->acc); + } + + return (0); +} + +static void +default_map_rules(struct gen_p *irs) { + /* Install time honoured and proved BSD style rules as default. */ + add_rule(irs, irs_gr, irs_lcl, ""); + add_rule(irs, irs_pw, irs_lcl, ""); + add_rule(irs, irs_sv, irs_lcl, ""); + add_rule(irs, irs_pr, irs_lcl, ""); + add_rule(irs, irs_ho, irs_dns, "continue"); + add_rule(irs, irs_ho, irs_lcl, ""); + add_rule(irs, irs_nw, irs_dns, "continue"); + add_rule(irs, irs_nw, irs_lcl, ""); + add_rule(irs, irs_ng, irs_lcl, ""); +} + +static void +init_map_rules(struct gen_p *irs, const char *conf_file) { + char line[1024], pattern[40], mapname[20], accname[20], options[100]; + FILE *conf; + + if (conf_file == NULL) + conf_file = _PATH_IRS_CONF ; + + /* A conf file of "" means compiled in defaults. Irpd wants this */ + if (conf_file[0] == '\0' || (conf = fopen(conf_file, "r")) == NULL) { + default_map_rules(irs); + return; + } + (void) sprintf(pattern, "%%%lus %%%lus %%%lus\n", + (unsigned long)sizeof mapname, + (unsigned long)sizeof accname, + (unsigned long)sizeof options); + while (fgets(line, sizeof line, conf)) { + enum irs_map_id map; + enum irs_acc_id acc; + char *tmp; + int n; + + for (tmp = line; + isascii((unsigned char)*tmp) && + isspace((unsigned char)*tmp); + tmp++) + (void)NULL; + if (*tmp == '#' || *tmp == '\n' || *tmp == '\0') + continue; + n = sscanf(tmp, pattern, mapname, accname, options); + if (n < 2) + continue; + if (n < 3) + options[0] = '\0'; + + n = find_name(mapname, map_names); + INSIST(n < irs_nmap); + if (n < 0) + continue; + map = (enum irs_map_id) n; + + n = find_name(accname, acc_names); + INSIST(n < irs_nacc); + if (n < 0) + continue; + acc = (enum irs_acc_id) n; + + add_rule(irs, map, acc, options); + } + fclose(conf); +} diff --git a/contrib/bind-9.5.2/lib/bind/irs/gen_gr.c b/contrib/bind-9.5.2/lib/bind/irs/gen_gr.c new file mode 100644 index 0000000000..d689e19319 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/gen_gr.c @@ -0,0 +1,493 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: gen_gr.c,v 1.8 2005/04/27 04:56:23 sra Exp $"; +#endif + +/* Imports */ + +#include "port_before.h" + +#ifndef WANT_IRS_GR +static int __bind_irs_gr_unneeded; +#else + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "gen_p.h" + +/* Definitions */ + +struct pvt { + struct irs_rule * rules; + struct irs_rule * rule; + struct irs_gr * gr; + /* + * Need space to store the entries read from the group file. + * The members list also needs space per member, and the + * strings making up the user names must be allocated + * somewhere. Rather than doing lots of small allocations, + * we keep one buffer and resize it as needed. + */ + struct group group; + size_t nmemb; /*%< Malloc'd max index of gr_mem[]. */ + char * membuf; + size_t membufsize; + struct __res_state * res; + void (*free_res)(void *); +}; + +/* Forward */ + +static void gr_close(struct irs_gr *); +static struct group * gr_next(struct irs_gr *); +static struct group * gr_byname(struct irs_gr *, const char *); +static struct group * gr_bygid(struct irs_gr *, gid_t); +static void gr_rewind(struct irs_gr *); +static int gr_list(struct irs_gr *, const char *, + gid_t, gid_t *, int *); +static void gr_minimize(struct irs_gr *); +static struct __res_state * gr_res_get(struct irs_gr *); +static void gr_res_set(struct irs_gr *, + struct __res_state *, + void (*)(void *)); + +static int grmerge(struct irs_gr *gr, const struct group *src, + int preserve); + +static int countvec(char **vec); +static int isnew(char **old, char *new); +static int countnew(char **old, char **new); +static size_t sizenew(char **old, char **new); +static int newgid(int, gid_t *, gid_t); + +/* Macros */ + +#define FREE_IF(x) do { if ((x) != NULL) { free(x); (x) = NULL; } } while (0) + +/* Public */ + +struct irs_gr * +irs_gen_gr(struct irs_acc *this) { + struct gen_p *accpvt = (struct gen_p *)this->private; + struct irs_gr *gr; + struct pvt *pvt; + + if (!(gr = memget(sizeof *gr))) { + errno = ENOMEM; + return (NULL); + } + memset(gr, 0x5e, sizeof *gr); + if (!(pvt = memget(sizeof *pvt))) { + memput(gr, sizeof *gr); + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + pvt->rules = accpvt->map_rules[irs_gr]; + pvt->rule = pvt->rules; + gr->private = pvt; + gr->close = gr_close; + gr->next = gr_next; + gr->byname = gr_byname; + gr->bygid = gr_bygid; + gr->rewind = gr_rewind; + gr->list = gr_list; + gr->minimize = gr_minimize; + gr->res_get = gr_res_get; + gr->res_set = gr_res_set; + return (gr); +} + +/* Methods. */ + +static void +gr_close(struct irs_gr *this) { + struct pvt *pvt = (struct pvt *)this->private; + + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct group * +gr_next(struct irs_gr *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct group *rval; + struct irs_gr *gr; + + while (pvt->rule) { + gr = pvt->rule->inst->gr; + rval = (*gr->next)(gr); + if (rval) + return (rval); + if (!(pvt->rule->flags & IRS_CONTINUE)) + break; + pvt->rule = pvt->rule->next; + if (pvt->rule) { + gr = pvt->rule->inst->gr; + (*gr->rewind)(gr); + } + } + return (NULL); +} + +static struct group * +gr_byname(struct irs_gr *this, const char *name) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + struct group *tval; + struct irs_gr *gr; + int dirty; + + dirty = 0; + for (rule = pvt->rules; rule; rule = rule->next) { + gr = rule->inst->gr; + tval = (*gr->byname)(gr, name); + if (tval) { + if (!grmerge(this, tval, dirty++)) + return (NULL); + if (!(rule->flags & IRS_MERGE)) + break; + } else { + if (!(rule->flags & IRS_CONTINUE)) + break; + } + } + if (dirty) + return (&pvt->group); + return (NULL); +} + +static struct group * +gr_bygid(struct irs_gr *this, gid_t gid) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + struct group *tval; + struct irs_gr *gr; + int dirty; + + dirty = 0; + for (rule = pvt->rules; rule; rule = rule->next) { + gr = rule->inst->gr; + tval = (*gr->bygid)(gr, gid); + if (tval) { + if (!grmerge(this, tval, dirty++)) + return (NULL); + if (!(rule->flags & IRS_MERGE)) + break; + } else { + if (!(rule->flags & IRS_CONTINUE)) + break; + } + } + if (dirty) + return (&pvt->group); + return (NULL); +} + +static void +gr_rewind(struct irs_gr *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_gr *gr; + + pvt->rule = pvt->rules; + if (pvt->rule) { + gr = pvt->rule->inst->gr; + (*gr->rewind)(gr); + } +} + +static int +gr_list(struct irs_gr *this, const char *name, + gid_t basegid, gid_t *groups, int *ngroups) +{ + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + struct irs_gr *gr; + int t_ngroups, maxgroups; + gid_t *t_groups; + int n, t, rval = 0; + + maxgroups = *ngroups; + *ngroups = 0; + t_groups = (gid_t *)malloc(maxgroups * sizeof(gid_t)); + if (!t_groups) { + errno = ENOMEM; + return (-1); + } + + for (rule = pvt->rules; rule; rule = rule->next) { + t_ngroups = maxgroups; + gr = rule->inst->gr; + t = (*gr->list)(gr, name, basegid, t_groups, &t_ngroups); + for (n = 0; n < t_ngroups; n++) { + if (newgid(*ngroups, groups, t_groups[n])) { + if (*ngroups == maxgroups) { + rval = -1; + goto done; + } + groups[(*ngroups)++] = t_groups[n]; + } + } + if (t == 0) { + if (!(rule->flags & IRS_MERGE)) + break; + } else { + if (!(rule->flags & IRS_CONTINUE)) + break; + } + } + done: + free(t_groups); + return (rval); +} + +static void +gr_minimize(struct irs_gr *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + + for (rule = pvt->rules; rule != NULL; rule = rule->next) { + struct irs_gr *gr = rule->inst->gr; + + (*gr->minimize)(gr); + } +} + +static struct __res_state * +gr_res_get(struct irs_gr *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->res) { + struct __res_state *res; + res = (struct __res_state *)malloc(sizeof *res); + if (!res) { + errno = ENOMEM; + return (NULL); + } + memset(res, 0, sizeof *res); + gr_res_set(this, res, free); + } + + return (pvt->res); +} + +static void +gr_res_set(struct irs_gr *this, struct __res_state *res, + void (*free_res)(void *)) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + + if (pvt->res && pvt->free_res) { + res_nclose(pvt->res); + (*pvt->free_res)(pvt->res); + } + + pvt->res = res; + pvt->free_res = free_res; + + for (rule = pvt->rules; rule != NULL; rule = rule->next) { + struct irs_gr *gr = rule->inst->gr; + + if (gr->res_set) + (*gr->res_set)(gr, pvt->res, NULL); + } +} + +/* Private. */ + +static int +grmerge(struct irs_gr *this, const struct group *src, int preserve) { + struct pvt *pvt = (struct pvt *)this->private; + char *cp, **m, **p, *oldmembuf, *ep; + int n, ndst, nnew; + size_t used; + + if (!preserve) { + pvt->group.gr_gid = src->gr_gid; + if (pvt->nmemb < 1) { + m = malloc(sizeof *m); + if (m == NULL) { + /* No harm done, no work done. */ + return (0); + } + pvt->group.gr_mem = m; + pvt->nmemb = 1; + } + pvt->group.gr_mem[0] = NULL; + } + ndst = countvec(pvt->group.gr_mem); + nnew = countnew(pvt->group.gr_mem, src->gr_mem); + + /* + * Make sure destination member array is large enough. + * p points to new portion. + */ + n = ndst + nnew + 1; + if ((size_t)n > pvt->nmemb) { + m = realloc(pvt->group.gr_mem, n * sizeof *m); + if (m == NULL) { + /* No harm done, no work done. */ + return (0); + } + pvt->group.gr_mem = m; + pvt->nmemb = n; + } + p = pvt->group.gr_mem + ndst; + + /* + * Enlarge destination membuf; cp points at new portion. + */ + n = sizenew(pvt->group.gr_mem, src->gr_mem); + INSIST((nnew == 0) == (n == 0)); + if (!preserve) { + n += strlen(src->gr_name) + 1; + n += strlen(src->gr_passwd) + 1; + } + if (n == 0) { + /* No work to do. */ + return (1); + } + used = preserve ? pvt->membufsize : 0; + cp = malloc(used + n); + if (cp == NULL) { + /* No harm done, no work done. */ + return (0); + } + ep = cp + used + n; + if (used != 0) + memcpy(cp, pvt->membuf, used); + oldmembuf = pvt->membuf; + pvt->membuf = cp; + pvt->membufsize = used + n; + cp += used; + + /* + * Adjust group.gr_mem. + */ + if (pvt->membuf != oldmembuf) + for (m = pvt->group.gr_mem; *m; m++) + *m = pvt->membuf + (*m - oldmembuf); + + /* + * Add new elements. + */ + for (m = src->gr_mem; *m; m++) + if (isnew(pvt->group.gr_mem, *m)) { + *p++ = cp; + *p = NULL; + n = strlen(*m) + 1; + if (n > ep - cp) { + FREE_IF(oldmembuf); + return (0); + } + strcpy(cp, *m); /* (checked) */ + cp += n; + } + if (preserve) { + pvt->group.gr_name = pvt->membuf + + (pvt->group.gr_name - oldmembuf); + pvt->group.gr_passwd = pvt->membuf + + (pvt->group.gr_passwd - oldmembuf); + } else { + pvt->group.gr_name = cp; + n = strlen(src->gr_name) + 1; + if (n > ep - cp) { + FREE_IF(oldmembuf); + return (0); + } + strcpy(cp, src->gr_name); /* (checked) */ + cp += n; + + pvt->group.gr_passwd = cp; + n = strlen(src->gr_passwd) + 1; + if (n > ep - cp) { + FREE_IF(oldmembuf); + return (0); + } + strcpy(cp, src->gr_passwd); /* (checked) */ + cp += n; + } + FREE_IF(oldmembuf); + INSIST(cp >= pvt->membuf && cp <= &pvt->membuf[pvt->membufsize]); + return (1); +} + +static int +countvec(char **vec) { + int n = 0; + + while (*vec++) + n++; + return (n); +} + +static int +isnew(char **old, char *new) { + for (; *old; old++) + if (strcmp(*old, new) == 0) + return (0); + return (1); +} + +static int +countnew(char **old, char **new) { + int n = 0; + + for (; *new; new++) + n += isnew(old, *new); + return (n); +} + +static size_t +sizenew(char **old, char **new) { + size_t n = 0; + + for (; *new; new++) + if (isnew(old, *new)) + n += strlen(*new) + 1; + return (n); +} + +static int +newgid(int ngroups, gid_t *groups, gid_t group) { + ngroups--, groups++; + for (; ngroups-- > 0; groups++) + if (*groups == group) + return (0); + return (1); +} + +#endif /* WANT_IRS_GR */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/gen_ho.c b/contrib/bind-9.5.2/lib/bind/irs/gen_ho.c new file mode 100644 index 0000000000..d38ea26b86 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/gen_ho.c @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: gen_ho.c,v 1.5 2006/03/09 23:57:56 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* Imports */ + +#include "port_before.h" + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "gen_p.h" + +/* Definitions */ + +struct pvt { + struct irs_rule * rules; + struct irs_rule * rule; + struct irs_ho * ho; + struct __res_state * res; + void (*free_res)(void *); +}; + +/* Forwards */ + +static void ho_close(struct irs_ho *this); +static struct hostent * ho_byname(struct irs_ho *this, const char *name); +static struct hostent * ho_byname2(struct irs_ho *this, const char *name, + int af); +static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr, + int len, int af); +static struct hostent * ho_next(struct irs_ho *this); +static void ho_rewind(struct irs_ho *this); +static void ho_minimize(struct irs_ho *this); +static struct __res_state * ho_res_get(struct irs_ho *this); +static void ho_res_set(struct irs_ho *this, + struct __res_state *res, + void (*free_res)(void *)); +static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name, + const struct addrinfo *pai); + +static int init(struct irs_ho *this); + +/* Exports */ + +struct irs_ho * +irs_gen_ho(struct irs_acc *this) { + struct gen_p *accpvt = (struct gen_p *)this->private; + struct irs_ho *ho; + struct pvt *pvt; + + if (!(pvt = memget(sizeof *pvt))) { + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + if (!(ho = memget(sizeof *ho))) { + memput(pvt, sizeof *pvt); + errno = ENOMEM; + return (NULL); + } + memset(ho, 0x5e, sizeof *ho); + pvt->rules = accpvt->map_rules[irs_ho]; + pvt->rule = pvt->rules; + ho->private = pvt; + ho->close = ho_close; + ho->byname = ho_byname; + ho->byname2 = ho_byname2; + ho->byaddr = ho_byaddr; + ho->next = ho_next; + ho->rewind = ho_rewind; + ho->minimize = ho_minimize; + ho->res_get = ho_res_get; + ho->res_set = ho_res_set; + ho->addrinfo = ho_addrinfo; + return (ho); +} + +/* Methods. */ + +static void +ho_close(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + + ho_minimize(this); + if (pvt->res && pvt->free_res) + (*pvt->free_res)(pvt->res); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct hostent * +ho_byname(struct irs_ho *this, const char *name) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + struct hostent *rval; + struct irs_ho *ho; + int therrno = NETDB_INTERNAL; + int softerror = 0; + + if (init(this) == -1) + return (NULL); + + for (rule = pvt->rules; rule; rule = rule->next) { + ho = rule->inst->ho; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + errno = 0; + rval = (*ho->byname)(ho, name); + if (rval != NULL) + return (rval); + if (softerror == 0 && + pvt->res->res_h_errno != HOST_NOT_FOUND && + pvt->res->res_h_errno != NETDB_INTERNAL) { + softerror = 1; + therrno = pvt->res->res_h_errno; + } + if (rule->flags & IRS_CONTINUE) + continue; + /* + * The value TRY_AGAIN can mean that the service + * is not available, or just that this particular name + * cannot be resolved now. We use the errno ECONNREFUSED + * to distinguish. If a lookup sets that errno when + * H_ERRNO is TRY_AGAIN, we continue to try other lookup + * functions, otherwise we return the TRY_AGAIN error. + */ + if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED) + break; + } + if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND) + RES_SET_H_ERRNO(pvt->res, therrno); + return (NULL); +} + +static struct hostent * +ho_byname2(struct irs_ho *this, const char *name, int af) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + struct hostent *rval; + struct irs_ho *ho; + int therrno = NETDB_INTERNAL; + int softerror = 0; + + if (init(this) == -1) + return (NULL); + + for (rule = pvt->rules; rule; rule = rule->next) { + ho = rule->inst->ho; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + errno = 0; + rval = (*ho->byname2)(ho, name, af); + if (rval != NULL) + return (rval); + if (softerror == 0 && + pvt->res->res_h_errno != HOST_NOT_FOUND && + pvt->res->res_h_errno != NETDB_INTERNAL) { + softerror = 1; + therrno = pvt->res->res_h_errno; + } + if (rule->flags & IRS_CONTINUE) + continue; + /* + * See the comments in ho_byname() explaining + * the interpretation of TRY_AGAIN and ECONNREFUSED. + */ + if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED) + break; + } + if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND) + RES_SET_H_ERRNO(pvt->res, therrno); + return (NULL); +} + +static struct hostent * +ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + struct hostent *rval; + struct irs_ho *ho; + int therrno = NETDB_INTERNAL; + int softerror = 0; + + + if (init(this) == -1) + return (NULL); + + for (rule = pvt->rules; rule; rule = rule->next) { + ho = rule->inst->ho; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + errno = 0; + rval = (*ho->byaddr)(ho, addr, len, af); + if (rval != NULL) + return (rval); + if (softerror == 0 && + pvt->res->res_h_errno != HOST_NOT_FOUND && + pvt->res->res_h_errno != NETDB_INTERNAL) { + softerror = 1; + therrno = pvt->res->res_h_errno; + } + + if (rule->flags & IRS_CONTINUE) + continue; + /* + * See the comments in ho_byname() explaining + * the interpretation of TRY_AGAIN and ECONNREFUSED. + */ + if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED) + break; + } + if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND) + RES_SET_H_ERRNO(pvt->res, therrno); + return (NULL); +} + +static struct hostent * +ho_next(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct hostent *rval; + struct irs_ho *ho; + + while (pvt->rule) { + ho = pvt->rule->inst->ho; + rval = (*ho->next)(ho); + if (rval) + return (rval); + if (!(pvt->rule->flags & IRS_CONTINUE)) + break; + pvt->rule = pvt->rule->next; + if (pvt->rule) { + ho = pvt->rule->inst->ho; + (*ho->rewind)(ho); + } + } + return (NULL); +} + +static void +ho_rewind(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_ho *ho; + + pvt->rule = pvt->rules; + if (pvt->rule) { + ho = pvt->rule->inst->ho; + (*ho->rewind)(ho); + } +} + +static void +ho_minimize(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + + if (pvt->res) + res_nclose(pvt->res); + for (rule = pvt->rules; rule != NULL; rule = rule->next) { + struct irs_ho *ho = rule->inst->ho; + + (*ho->minimize)(ho); + } +} + +static struct __res_state * +ho_res_get(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->res) { + struct __res_state *res; + res = (struct __res_state *)malloc(sizeof *res); + if (!res) { + errno = ENOMEM; + return (NULL); + } + memset(res, 0, sizeof *res); + ho_res_set(this, res, free); + } + + return (pvt->res); +} + +static void +ho_res_set(struct irs_ho *this, struct __res_state *res, + void (*free_res)(void *)) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + + if (pvt->res && pvt->free_res) { + res_nclose(pvt->res); + (*pvt->free_res)(pvt->res); + } + + pvt->res = res; + pvt->free_res = free_res; + + for (rule = pvt->rules; rule != NULL; rule = rule->next) { + struct irs_ho *ho = rule->inst->ho; + + (*ho->res_set)(ho, pvt->res, NULL); + } +} + +static struct addrinfo * +ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai) +{ + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + struct addrinfo *rval = NULL; + struct irs_ho *ho; + int therrno = NETDB_INTERNAL; + int softerror = 0; + + if (init(this) == -1) + return (NULL); + + for (rule = pvt->rules; rule; rule = rule->next) { + ho = rule->inst->ho; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + errno = 0; + if (ho->addrinfo == NULL) /*%< for safety */ + continue; + rval = (*ho->addrinfo)(ho, name, pai); + if (rval != NULL) + return (rval); + if (softerror == 0 && + pvt->res->res_h_errno != HOST_NOT_FOUND && + pvt->res->res_h_errno != NETDB_INTERNAL) { + softerror = 1; + therrno = pvt->res->res_h_errno; + } + if (rule->flags & IRS_CONTINUE) + continue; + /* + * See the comments in ho_byname() explaining + * the interpretation of TRY_AGAIN and ECONNREFUSED. + */ + if (pvt->res->res_h_errno != TRY_AGAIN || + errno != ECONNREFUSED) + break; + } + if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND) + RES_SET_H_ERRNO(pvt->res, therrno); + return (NULL); +} + +static int +init(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->res && !ho_res_get(this)) + return (-1); + + if (((pvt->res->options & RES_INIT) == 0U) && + (res_ninit(pvt->res) == -1)) + return (-1); + + return (0); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/gen_ng.c b/contrib/bind-9.5.2/lib/bind/irs/gen_ng.c new file mode 100644 index 0000000000..c617c7c9f5 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/gen_ng.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: gen_ng.c,v 1.3 2005/04/27 04:56:23 sra Exp $"; +#endif + +/* Imports */ + +#include "port_before.h" + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "gen_p.h" + +/* Types */ + +struct pvt { + struct irs_rule * rules; + struct irs_rule * rule; + char * curgroup; +}; + +/* Forward */ + +static void ng_close(struct irs_ng *); +static int ng_next(struct irs_ng *, const char **, + const char **, const char **); +static int ng_test(struct irs_ng *, const char *, + const char *, const char *, + const char *); +static void ng_rewind(struct irs_ng *, const char *); +static void ng_minimize(struct irs_ng *); + +/* Public */ + +struct irs_ng * +irs_gen_ng(struct irs_acc *this) { + struct gen_p *accpvt = (struct gen_p *)this->private; + struct irs_ng *ng; + struct pvt *pvt; + + if (!(ng = memget(sizeof *ng))) { + errno = ENOMEM; + return (NULL); + } + memset(ng, 0x5e, sizeof *ng); + if (!(pvt = memget(sizeof *pvt))) { + memput(ng, sizeof *ng); + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + pvt->rules = accpvt->map_rules[irs_ng]; + pvt->rule = pvt->rules; + ng->private = pvt; + ng->close = ng_close; + ng->next = ng_next; + ng->test = ng_test; + ng->rewind = ng_rewind; + ng->minimize = ng_minimize; + return (ng); +} + +/* Methods */ + +static void +ng_close(struct irs_ng *this) { + struct pvt *pvt = (struct pvt *)this->private; + + ng_minimize(this); + if (pvt->curgroup) + free(pvt->curgroup); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static int +ng_next(struct irs_ng *this, const char **host, const char **user, + const char **domain) +{ + struct pvt *pvt = (struct pvt *)this->private; + struct irs_ng *ng; + + while (pvt->rule) { + ng = pvt->rule->inst->ng; + if ((*ng->next)(ng, host, user, domain) == 1) + return (1); + if (!(pvt->rule->flags & IRS_CONTINUE)) + break; + pvt->rule = pvt->rule->next; + if (pvt->rule) { + ng = pvt->rule->inst->ng; + (*ng->rewind)(ng, pvt->curgroup); + } + } + return (0); +} + +static int +ng_test(struct irs_ng *this, const char *name, + const char *user, const char *host, const char *domain) +{ + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + struct irs_ng *ng; + int rval; + + rval = 0; + for (rule = pvt->rules; rule; rule = rule->next) { + ng = rule->inst->ng; + rval = (*ng->test)(ng, name, user, host, domain); + if (rval || !(rule->flags & IRS_CONTINUE)) + break; + } + return (rval); +} + +static void +ng_rewind(struct irs_ng *this, const char *group) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_ng *ng; + + pvt->rule = pvt->rules; + if (pvt->rule) { + if (pvt->curgroup) + free(pvt->curgroup); + pvt->curgroup = strdup(group); + ng = pvt->rule->inst->ng; + (*ng->rewind)(ng, pvt->curgroup); + } +} + +static void +ng_minimize(struct irs_ng *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + + for (rule = pvt->rules; rule != NULL; rule = rule->next) { + struct irs_ng *ng = rule->inst->ng; + + (*ng->minimize)(ng); + } +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/gen_nw.c b/contrib/bind-9.5.2/lib/bind/irs/gen_nw.c new file mode 100644 index 0000000000..480a435478 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/gen_nw.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: gen_nw.c,v 1.4 2005/04/27 04:56:23 sra Exp $"; +#endif + +/* Imports */ + +#include "port_before.h" + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "gen_p.h" + +/* Types */ + +struct pvt { + struct irs_rule * rules; + struct irs_rule * rule; + struct __res_state * res; + void (*free_res)(void *); +}; + +/* Forward */ + +static void nw_close(struct irs_nw*); +static struct nwent * nw_next(struct irs_nw *); +static struct nwent * nw_byname(struct irs_nw *, const char *, int); +static struct nwent * nw_byaddr(struct irs_nw *, void *, int, int); +static void nw_rewind(struct irs_nw *); +static void nw_minimize(struct irs_nw *); +static struct __res_state * nw_res_get(struct irs_nw *this); +static void nw_res_set(struct irs_nw *this, + struct __res_state *res, + void (*free_res)(void *)); + +static int init(struct irs_nw *this); + +/* Public */ + +struct irs_nw * +irs_gen_nw(struct irs_acc *this) { + struct gen_p *accpvt = (struct gen_p *)this->private; + struct irs_nw *nw; + struct pvt *pvt; + + if (!(pvt = memget(sizeof *pvt))) { + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + if (!(nw = memget(sizeof *nw))) { + memput(pvt, sizeof *pvt); + errno = ENOMEM; + return (NULL); + } + memset(nw, 0x5e, sizeof *nw); + pvt->rules = accpvt->map_rules[irs_nw]; + pvt->rule = pvt->rules; + nw->private = pvt; + nw->close = nw_close; + nw->next = nw_next; + nw->byname = nw_byname; + nw->byaddr = nw_byaddr; + nw->rewind = nw_rewind; + nw->minimize = nw_minimize; + nw->res_get = nw_res_get; + nw->res_set = nw_res_set; + return (nw); +} + +/* Methods */ + +static void +nw_close(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + nw_minimize(this); + + if (pvt->res && pvt->free_res) + (*pvt->free_res)(pvt->res); + + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct nwent * +nw_next(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct nwent *rval; + struct irs_nw *nw; + + if (init(this) == -1) + return(NULL); + + while (pvt->rule) { + nw = pvt->rule->inst->nw; + rval = (*nw->next)(nw); + if (rval) + return (rval); + if (!(pvt->rules->flags & IRS_CONTINUE)) + break; + pvt->rule = pvt->rule->next; + if (pvt->rule) { + nw = pvt->rule->inst->nw; + (*nw->rewind)(nw); + } + } + return (NULL); +} + +static struct nwent * +nw_byname(struct irs_nw *this, const char *name, int type) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + struct nwent *rval; + struct irs_nw *nw; + + if (init(this) == -1) + return(NULL); + + for (rule = pvt->rules; rule; rule = rule->next) { + nw = rule->inst->nw; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + rval = (*nw->byname)(nw, name, type); + if (rval != NULL) + return (rval); + if (pvt->res->res_h_errno != TRY_AGAIN && + !(rule->flags & IRS_CONTINUE)) + break; + } + return (NULL); +} + +static struct nwent * +nw_byaddr(struct irs_nw *this, void *net, int length, int type) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + struct nwent *rval; + struct irs_nw *nw; + + if (init(this) == -1) + return(NULL); + + for (rule = pvt->rules; rule; rule = rule->next) { + nw = rule->inst->nw; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + rval = (*nw->byaddr)(nw, net, length, type); + if (rval != NULL) + return (rval); + if (pvt->res->res_h_errno != TRY_AGAIN && + !(rule->flags & IRS_CONTINUE)) + break; + } + return (NULL); +} + +static void +nw_rewind(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_nw *nw; + + pvt->rule = pvt->rules; + if (pvt->rule) { + nw = pvt->rule->inst->nw; + (*nw->rewind)(nw); + } +} + +static void +nw_minimize(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + + if (pvt->res) + res_nclose(pvt->res); + for (rule = pvt->rules; rule != NULL; rule = rule->next) { + struct irs_nw *nw = rule->inst->nw; + + (*nw->minimize)(nw); + } +} + +static struct __res_state * +nw_res_get(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->res) { + struct __res_state *res; + res = (struct __res_state *)malloc(sizeof *res); + if (!res) { + errno = ENOMEM; + return (NULL); + } + memset(res, 0, sizeof *res); + nw_res_set(this, res, free); + } + + return (pvt->res); +} + +static void +nw_res_set(struct irs_nw *this, struct __res_state *res, + void (*free_res)(void *)) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + + if (pvt->res && pvt->free_res) { + res_nclose(pvt->res); + (*pvt->free_res)(pvt->res); + } + + pvt->res = res; + pvt->free_res = free_res; + + for (rule = pvt->rules; rule != NULL; rule = rule->next) { + struct irs_nw *nw = rule->inst->nw; + + (*nw->res_set)(nw, pvt->res, NULL); + } +} + +static int +init(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->res && !nw_res_get(this)) + return (-1); + if (((pvt->res->options & RES_INIT) == 0U) && + res_ninit(pvt->res) == -1) + return (-1); + return (0); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/gen_p.h b/contrib/bind-9.5.2/lib/bind/irs/gen_p.h new file mode 100644 index 0000000000..1adc5909bb --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/gen_p.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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: gen_p.h,v 1.3 2005/04/27 04:56:23 sra Exp $ + */ + +/*! \file + * Notes: + * We hope to create a complete set of thread-safe entry points someday, + * which will mean a set of getXbyY() functions that take as an argument + * a pointer to the map class, which will have a pointer to the private + * data, which will be used preferentially to the static variables that + * are necessary to support the "classic" interface. This "classic" + * interface will then be reimplemented as stubs on top of the thread + * safe modules, and will keep the map class pointers as their only + * static data. HOWEVER, we are not there yet. So while we will call + * the just-barely-converted map class methods with map class pointers, + * right now they probably all still use statics. We're not fooling + * anybody, and we're not trying to (yet). + */ + +#ifndef _GEN_P_H_INCLUDED +#define _GEN_P_H_INCLUDED + +/*% + * These are the access methods. + */ +enum irs_acc_id { + irs_lcl, /*%< Local. */ + irs_dns, /*%< DNS or Hesiod. */ + irs_nis, /*%< Sun NIS ("YP"). */ + irs_irp, /*%< IR protocol. */ + irs_nacc +}; + +/*% + * These are the map types. + */ +enum irs_map_id { + irs_gr, /*%< "group" */ + irs_pw, /*%< "passwd" */ + irs_sv, /*%< "services" */ + irs_pr, /*%< "protocols" */ + irs_ho, /*%< "hosts" */ + irs_nw, /*%< "networks" */ + irs_ng, /*%< "netgroup" */ + irs_nmap +}; + +/*% + * This is an accessor instance. + */ +struct irs_inst { + struct irs_acc *acc; + struct irs_gr * gr; + struct irs_pw * pw; + struct irs_sv * sv; + struct irs_pr * pr; + struct irs_ho * ho; + struct irs_nw * nw; + struct irs_ng * ng; +}; + +/*% + * This is a search rule for some map type. + */ +struct irs_rule { + struct irs_rule * next; + struct irs_inst * inst; + int flags; +}; +#define IRS_MERGE 0x0001 /*%< Don't stop if acc. has data? */ +#define IRS_CONTINUE 0x0002 /*%< Don't stop if acc. has no data? */ +/* + * This is the private data for a search access class. + */ +struct gen_p { + char * options; + struct irs_rule * map_rules[(int)irs_nmap]; + struct irs_inst accessors[(int)irs_nacc]; + struct __res_state * res; + void (*free_res) __P((void *)); +}; + +/* + * Externs. + */ + +extern struct irs_acc * irs_gen_acc __P((const char *, const char *conf_file)); +extern struct irs_gr * irs_gen_gr __P((struct irs_acc *)); +extern struct irs_pw * irs_gen_pw __P((struct irs_acc *)); +extern struct irs_sv * irs_gen_sv __P((struct irs_acc *)); +extern struct irs_pr * irs_gen_pr __P((struct irs_acc *)); +extern struct irs_ho * irs_gen_ho __P((struct irs_acc *)); +extern struct irs_nw * irs_gen_nw __P((struct irs_acc *)); +extern struct irs_ng * irs_gen_ng __P((struct irs_acc *)); + +#endif /*_IRS_P_H_INCLUDED*/ diff --git a/contrib/bind-9.5.2/lib/bind/irs/gen_pr.c b/contrib/bind-9.5.2/lib/bind/irs/gen_pr.c new file mode 100644 index 0000000000..93c0426c78 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/gen_pr.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: gen_pr.c,v 1.3 2005/04/27 04:56:24 sra Exp $"; +#endif + +/* Imports */ + +#include "port_before.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "gen_p.h" + +/* Types */ + +struct pvt { + struct irs_rule * rules; + struct irs_rule * rule; + struct __res_state * res; + void (*free_res)(void *); +}; + +/* Forward */ + +static void pr_close(struct irs_pr*); +static struct protoent * pr_next(struct irs_pr *); +static struct protoent * pr_byname(struct irs_pr *, const char *); +static struct protoent * pr_bynumber(struct irs_pr *, int); +static void pr_rewind(struct irs_pr *); +static void pr_minimize(struct irs_pr *); +static struct __res_state * pr_res_get(struct irs_pr *); +static void pr_res_set(struct irs_pr *, + struct __res_state *, + void (*)(void *)); + +/* Public */ + +struct irs_pr * +irs_gen_pr(struct irs_acc *this) { + struct gen_p *accpvt = (struct gen_p *)this->private; + struct irs_pr *pr; + struct pvt *pvt; + + if (!(pr = memget(sizeof *pr))) { + errno = ENOMEM; + return (NULL); + } + memset(pr, 0x5e, sizeof *pr); + if (!(pvt = memget(sizeof *pvt))) { + memput(pr, sizeof *pr); + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + pvt->rules = accpvt->map_rules[irs_pr]; + pvt->rule = pvt->rules; + pr->private = pvt; + pr->close = pr_close; + pr->next = pr_next; + pr->byname = pr_byname; + pr->bynumber = pr_bynumber; + pr->rewind = pr_rewind; + pr->minimize = pr_minimize; + pr->res_get = pr_res_get; + pr->res_set = pr_res_set; + return (pr); +} + +/* Methods */ + +static void +pr_close(struct irs_pr *this) { + struct pvt *pvt = (struct pvt *)this->private; + + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct protoent * +pr_next(struct irs_pr *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct protoent *rval; + struct irs_pr *pr; + + while (pvt->rule) { + pr = pvt->rule->inst->pr; + rval = (*pr->next)(pr); + if (rval) + return (rval); + if (!(pvt->rules->flags & IRS_CONTINUE)) + break; + pvt->rule = pvt->rule->next; + if (pvt->rule) { + pr = pvt->rule->inst->pr; + (*pr->rewind)(pr); + } + } + return (NULL); +} + +static struct protoent * +pr_byname(struct irs_pr *this, const char *name) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + struct protoent *rval; + struct irs_pr *pr; + + rval = NULL; + for (rule = pvt->rules; rule; rule = rule->next) { + pr = rule->inst->pr; + rval = (*pr->byname)(pr, name); + if (rval || !(rule->flags & IRS_CONTINUE)) + break; + } + return (rval); +} + +static struct protoent * +pr_bynumber(struct irs_pr *this, int proto) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + struct protoent *rval; + struct irs_pr *pr; + + rval = NULL; + for (rule = pvt->rules; rule; rule = rule->next) { + pr = rule->inst->pr; + rval = (*pr->bynumber)(pr, proto); + if (rval || !(rule->flags & IRS_CONTINUE)) + break; + } + return (rval); +} + +static void +pr_rewind(struct irs_pr *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_pr *pr; + + pvt->rule = pvt->rules; + if (pvt->rule) { + pr = pvt->rule->inst->pr; + (*pr->rewind)(pr); + } +} + +static void +pr_minimize(struct irs_pr *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + + for (rule = pvt->rules; rule != NULL; rule = rule->next) { + struct irs_pr *pr = rule->inst->pr; + + (*pr->minimize)(pr); + } +} + +static struct __res_state * +pr_res_get(struct irs_pr *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->res) { + struct __res_state *res; + res = (struct __res_state *)malloc(sizeof *res); + if (!res) { + errno = ENOMEM; + return (NULL); + } + memset(res, 0, sizeof *res); + pr_res_set(this, res, free); + } + + return (pvt->res); +} + +static void +pr_res_set(struct irs_pr *this, struct __res_state *res, + void (*free_res)(void *)) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + + if (pvt->res && pvt->free_res) { + res_nclose(pvt->res); + (*pvt->free_res)(pvt->res); + } + + pvt->res = res; + pvt->free_res = free_res; + + for (rule = pvt->rules; rule != NULL; rule = rule->next) { + struct irs_pr *pr = rule->inst->pr; + + if (pr->res_set) + (*pr->res_set)(pr, pvt->res, NULL); + } +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/gen_pw.c b/contrib/bind-9.5.2/lib/bind/irs/gen_pw.c new file mode 100644 index 0000000000..512b011518 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/gen_pw.c @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: gen_pw.c,v 1.3 2005/04/27 04:56:24 sra Exp $"; +#endif + +/* Imports */ + +#include "port_before.h" + +#ifndef WANT_IRS_PW +static int __bind_irs_pw_unneeded; +#else + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "gen_p.h" + +/* Types */ + +struct pvt { + struct irs_rule * rules; + struct irs_rule * rule; + struct __res_state * res; + void (*free_res)(void *); +}; + +/* Forward */ + +static void pw_close(struct irs_pw *); +static struct passwd * pw_next(struct irs_pw *); +static struct passwd * pw_byname(struct irs_pw *, const char *); +static struct passwd * pw_byuid(struct irs_pw *, uid_t); +static void pw_rewind(struct irs_pw *); +static void pw_minimize(struct irs_pw *); +static struct __res_state * pw_res_get(struct irs_pw *); +static void pw_res_set(struct irs_pw *, + struct __res_state *, + void (*)(void *)); + +/* Public */ + +struct irs_pw * +irs_gen_pw(struct irs_acc *this) { + struct gen_p *accpvt = (struct gen_p *)this->private; + struct irs_pw *pw; + struct pvt *pvt; + + if (!(pw = memget(sizeof *pw))) { + errno = ENOMEM; + return (NULL); + } + memset(pw, 0x5e, sizeof *pw); + if (!(pvt = memget(sizeof *pvt))) { + memput(pw, sizeof *pvt); + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + pvt->rules = accpvt->map_rules[irs_pw]; + pvt->rule = pvt->rules; + pw->private = pvt; + pw->close = pw_close; + pw->next = pw_next; + pw->byname = pw_byname; + pw->byuid = pw_byuid; + pw->rewind = pw_rewind; + pw->minimize = pw_minimize; + pw->res_get = pw_res_get; + pw->res_set = pw_res_set; + return (pw); +} + +/* Methods */ + +static void +pw_close(struct irs_pw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct passwd * +pw_next(struct irs_pw *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct passwd *rval; + struct irs_pw *pw; + + while (pvt->rule) { + pw = pvt->rule->inst->pw; + rval = (*pw->next)(pw); + if (rval) + return (rval); + if (!(pvt->rule->flags & IRS_CONTINUE)) + break; + pvt->rule = pvt->rule->next; + if (pvt->rule) { + pw = pvt->rule->inst->pw; + (*pw->rewind)(pw); + } + } + return (NULL); +} + +static void +pw_rewind(struct irs_pw *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_pw *pw; + + pvt->rule = pvt->rules; + if (pvt->rule) { + pw = pvt->rule->inst->pw; + (*pw->rewind)(pw); + } +} + +static struct passwd * +pw_byname(struct irs_pw *this, const char *name) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + struct passwd *rval; + struct irs_pw *pw; + + rval = NULL; + for (rule = pvt->rules; rule; rule = rule->next) { + pw = rule->inst->pw; + rval = (*pw->byname)(pw, name); + if (rval || !(rule->flags & IRS_CONTINUE)) + break; + } + return (rval); +} + +static struct passwd * +pw_byuid(struct irs_pw *this, uid_t uid) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + struct passwd *rval; + struct irs_pw *pw; + + rval = NULL; + for (rule = pvt->rules; rule; rule = rule->next) { + pw = rule->inst->pw; + rval = (*pw->byuid)(pw, uid); + if (rval || !(rule->flags & IRS_CONTINUE)) + break; + } + return (rval); +} + +static void +pw_minimize(struct irs_pw *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + + for (rule = pvt->rules; rule != NULL; rule = rule->next) { + struct irs_pw *pw = rule->inst->pw; + + (*pw->minimize)(pw); + } +} + +static struct __res_state * +pw_res_get(struct irs_pw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->res) { + struct __res_state *res; + res = (struct __res_state *)malloc(sizeof *res); + if (!res) { + errno = ENOMEM; + return (NULL); + } + memset(res, 0, sizeof *res); + pw_res_set(this, res, free); + } + + return (pvt->res); +} + +static void +pw_res_set(struct irs_pw *this, struct __res_state *res, + void (*free_res)(void *)) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + + if (pvt->res && pvt->free_res) { + res_nclose(pvt->res); + (*pvt->free_res)(pvt->res); + } + + pvt->res = res; + pvt->free_res = free_res; + + for (rule = pvt->rules; rule != NULL; rule = rule->next) { + struct irs_pw *pw = rule->inst->pw; + + if (pw->res_set) + (*pw->res_set)(pw, pvt->res, NULL); + } +} + +#endif /* WANT_IRS_PW */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/gen_sv.c b/contrib/bind-9.5.2/lib/bind/irs/gen_sv.c new file mode 100644 index 0000000000..4cad166d2f --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/gen_sv.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: gen_sv.c,v 1.3 2005/04/27 04:56:24 sra Exp $"; +#endif + +/* Imports */ + +#include "port_before.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "gen_p.h" + +/* Types */ + +struct pvt { + struct irs_rule * rules; + struct irs_rule * rule; + struct __res_state * res; + void (*free_res)(void *); +}; + +/* Forward */ + +static void sv_close(struct irs_sv*); +static struct servent * sv_next(struct irs_sv *); +static struct servent * sv_byname(struct irs_sv *, const char *, + const char *); +static struct servent * sv_byport(struct irs_sv *, int, const char *); +static void sv_rewind(struct irs_sv *); +static void sv_minimize(struct irs_sv *); +static struct __res_state * sv_res_get(struct irs_sv *); +static void sv_res_set(struct irs_sv *, + struct __res_state *, + void (*)(void *)); + +/* Public */ + +struct irs_sv * +irs_gen_sv(struct irs_acc *this) { + struct gen_p *accpvt = (struct gen_p *)this->private; + struct irs_sv *sv; + struct pvt *pvt; + + if (!(sv = memget(sizeof *sv))) { + errno = ENOMEM; + return (NULL); + } + memset(sv, 0x5e, sizeof *sv); + if (!(pvt = memget(sizeof *pvt))) { + memput(sv, sizeof *sv); + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + pvt->rules = accpvt->map_rules[irs_sv]; + pvt->rule = pvt->rules; + sv->private = pvt; + sv->close = sv_close; + sv->next = sv_next; + sv->byname = sv_byname; + sv->byport = sv_byport; + sv->rewind = sv_rewind; + sv->minimize = sv_minimize; + sv->res_get = sv_res_get; + sv->res_set = sv_res_set; + return (sv); +} + +/* Methods */ + +static void +sv_close(struct irs_sv *this) { + struct pvt *pvt = (struct pvt *)this->private; + + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct servent * +sv_next(struct irs_sv *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct servent *rval; + struct irs_sv *sv; + + while (pvt->rule) { + sv = pvt->rule->inst->sv; + rval = (*sv->next)(sv); + if (rval) + return (rval); + if (!(pvt->rule->flags & IRS_CONTINUE)) + break; + pvt->rule = pvt->rule->next; + if (pvt->rule) { + sv = pvt->rule->inst->sv; + (*sv->rewind)(sv); + } + } + return (NULL); +} + +static struct servent * +sv_byname(struct irs_sv *this, const char *name, const char *proto) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + struct servent *rval; + struct irs_sv *sv; + + rval = NULL; + for (rule = pvt->rules; rule; rule = rule->next) { + sv = rule->inst->sv; + rval = (*sv->byname)(sv, name, proto); + if (rval || !(rule->flags & IRS_CONTINUE)) + break; + } + return (rval); +} + +static struct servent * +sv_byport(struct irs_sv *this, int port, const char *proto) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + struct servent *rval; + struct irs_sv *sv; + + rval = NULL; + for (rule = pvt->rules; rule; rule = rule->next) { + sv = rule->inst->sv; + rval = (*sv->byport)(sv, port, proto); + if (rval || !(rule->flags & IRS_CONTINUE)) + break; + } + return (rval); +} + +static void +sv_rewind(struct irs_sv *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_sv *sv; + + pvt->rule = pvt->rules; + if (pvt->rule) { + sv = pvt->rule->inst->sv; + (*sv->rewind)(sv); + } +} + +static void +sv_minimize(struct irs_sv *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + + for (rule = pvt->rules; rule != NULL; rule = rule->next) { + struct irs_sv *sv = rule->inst->sv; + + (*sv->minimize)(sv); + } +} + +static struct __res_state * +sv_res_get(struct irs_sv *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->res) { + struct __res_state *res; + res = (struct __res_state *)malloc(sizeof *res); + if (!res) { + errno = ENOMEM; + return (NULL); + } + memset(res, 0, sizeof *res); + sv_res_set(this, res, free); + } + + return (pvt->res); +} + +static void +sv_res_set(struct irs_sv *this, struct __res_state *res, + void (*free_res)(void *)) { + struct pvt *pvt = (struct pvt *)this->private; + struct irs_rule *rule; + + if (pvt->res && pvt->free_res) { + res_nclose(pvt->res); + (*pvt->free_res)(pvt->res); + } + + pvt->res = res; + pvt->free_res = free_res; + + for (rule = pvt->rules; rule != NULL; rule = rule->next) { + struct irs_sv *sv = rule->inst->sv; + + if (sv->res_set) + (*sv->res_set)(sv, pvt->res, NULL); + } +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/getaddrinfo.c b/contrib/bind-9.5.2/lib/bind/irs/getaddrinfo.c new file mode 100644 index 0000000000..1839ba48e1 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/getaddrinfo.c @@ -0,0 +1,1253 @@ +/* $KAME: getaddrinfo.c,v 1.14 2001/01/06 09:41:15 jinmei Exp $ */ + +/* + * 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. + */ + +/*! \file + * Issues to be discussed: + *\li Thread safe-ness must be checked. + *\li Return values. There are nonstandard return values defined and used + * in the source code. This is because RFC2553 is silent about which error + * code must be returned for which situation. + *\li IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2 + * says to use inet_aton() to convert IPv4 numeric to binary (allows + * classful form as a result). + * current code - disallow classful form for IPv4 (due to use of inet_pton). + *\li freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is + * invalid. + * current code - SEGV on freeaddrinfo(NULL) + * Note: + *\li We use getipnodebyname() just for thread-safeness. There's no intent + * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to + * getipnodebyname(). + *\li The code filters out AFs that are not supported by the kernel, + * when globbing NULL hostname (to loopback, or wildcard). Is it the right + * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG + * in ai_flags? + *\li (post-2553) semantics of AI_ADDRCONFIG itself is too vague. + * (1) what should we do against numeric hostname (2) what should we do + * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? + * non-loopback address configured? global address configured? + * \par Additional Issue: + * To avoid search order issue, we have a big amount of code duplicate + * from gethnamaddr.c and some other places. The issues that there's no + * lower layer function to lookup "IPv4 or IPv6" record. Calling + * gethostbyname2 from getaddrinfo will end up in wrong search order, as + * follows: + * \li The code makes use of following calls when asked to resolver with + * ai_family = PF_UNSPEC: + *\code getipnodebyname(host, AF_INET6); + * getipnodebyname(host, AF_INET); + *\endcode + * \li This will result in the following queries if the node is configure to + * prefer /etc/hosts than DNS: + *\code + * lookup /etc/hosts for IPv6 address + * lookup DNS for IPv6 address + * lookup /etc/hosts for IPv4 address + * lookup DNS for IPv4 address + *\endcode + * which may not meet people's requirement. + * \li The right thing to happen is to have underlying layer which does + * PF_UNSPEC lookup (lookup both) and return chain of addrinfos. + * This would result in a bit of code duplicate with _dns_ghbyname() and + * friends. + */ + +#include "port_before.h" + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "port_after.h" + +#include "irs_data.h" + +#define SUCCESS 0 +#define ANY 0 +#define YES 1 +#define NO 0 + +static const char in_addrany[] = { 0, 0, 0, 0 }; +static const char in6_addrany[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +static const char in_loopback[] = { 127, 0, 0, 1 }; +static const char in6_loopback[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 +}; + +static const struct afd { + int a_af; + int a_addrlen; + int a_socklen; + int a_off; + const char *a_addrany; + const char *a_loopback; + int a_scoped; +} afdl [] = { + {PF_INET6, sizeof(struct in6_addr), + sizeof(struct sockaddr_in6), + offsetof(struct sockaddr_in6, sin6_addr), + in6_addrany, in6_loopback, 1}, + {PF_INET, sizeof(struct in_addr), + sizeof(struct sockaddr_in), + offsetof(struct sockaddr_in, sin_addr), + in_addrany, in_loopback, 0}, + {0, 0, 0, 0, NULL, NULL, 0}, +}; + +struct explore { + int e_af; + int e_socktype; + int e_protocol; + const char *e_protostr; + int e_wild; +#define WILD_AF(ex) ((ex)->e_wild & 0x01) +#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) +#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) +}; + +static const struct explore explore[] = { +#if 0 + { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, +#endif + { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, + { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, + { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, + { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, + { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, + { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, + { -1, 0, 0, NULL, 0 }, +}; + +#define PTON_MAX 16 + +static int str_isnumber __P((const char *)); +static int explore_fqdn __P((const struct addrinfo *, const char *, + const char *, struct addrinfo **)); +static int explore_copy __P((const struct addrinfo *, const struct addrinfo *, + struct addrinfo **)); +static int explore_null __P((const struct addrinfo *, + const char *, struct addrinfo **)); +static int explore_numeric __P((const struct addrinfo *, const char *, + const char *, struct addrinfo **)); +static int explore_numeric_scope __P((const struct addrinfo *, const char *, + const char *, struct addrinfo **)); +static int get_canonname __P((const struct addrinfo *, + struct addrinfo *, const char *)); +static struct addrinfo *get_ai __P((const struct addrinfo *, + const struct afd *, const char *)); +static struct addrinfo *copy_ai __P((const struct addrinfo *)); +static int get_portmatch __P((const struct addrinfo *, const char *)); +static int get_port __P((const struct addrinfo *, const char *, int)); +static const struct afd *find_afd __P((int)); +static int addrconfig __P((int)); +static int ip6_str2scopeid __P((char *, struct sockaddr_in6 *, + u_int32_t *scopeidp)); +static struct net_data *init __P((void)); + +struct addrinfo *hostent2addrinfo __P((struct hostent *, + const struct addrinfo *)); +struct addrinfo *addr2addrinfo __P((const struct addrinfo *, + const char *)); + +#if 0 +static const char *ai_errlist[] = { + "Success", + "Address family for hostname not supported", /*%< EAI_ADDRFAMILY */ + "Temporary failure in name resolution", /*%< EAI_AGAIN */ + "Invalid value for ai_flags", /*%< EAI_BADFLAGS */ + "Non-recoverable failure in name resolution", /*%< EAI_FAIL */ + "ai_family not supported", /*%< EAI_FAMILY */ + "Memory allocation failure", /*%< EAI_MEMORY */ + "No address associated with hostname", /*%< EAI_NODATA */ + "hostname nor servname provided, or not known", /*%< EAI_NONAME */ + "servname not supported for ai_socktype", /*%< EAI_SERVICE */ + "ai_socktype not supported", /*%< EAI_SOCKTYPE */ + "System error returned in errno", /*%< EAI_SYSTEM */ + "Invalid value for hints", /*%< EAI_BADHINTS */ + "Resolved protocol is unknown", /*%< EAI_PROTOCOL */ + "Unknown error", /*%< EAI_MAX */ +}; +#endif + +/* XXX macros that make external reference is BAD. */ + +#define GET_AI(ai, afd, addr) \ +do { \ + /* external reference: pai, error, and label free */ \ + (ai) = get_ai(pai, (afd), (addr)); \ + if ((ai) == NULL) { \ + error = EAI_MEMORY; \ + goto free; \ + } \ +} while (/*CONSTCOND*/0) + +#define GET_PORT(ai, serv) \ +do { \ + /* external reference: error and label free */ \ + error = get_port((ai), (serv), 0); \ + if (error != 0) \ + goto free; \ +} while (/*CONSTCOND*/0) + +#define GET_CANONNAME(ai, str) \ +do { \ + /* external reference: pai, error and label free */ \ + error = get_canonname(pai, (ai), (str)); \ + if (error != 0) \ + goto free; \ +} while (/*CONSTCOND*/0) + +#ifndef SOLARIS2 +#define SETERROR(err) \ +do { \ + /* external reference: error, and label bad */ \ + error = (err); \ + goto bad; \ + /*NOTREACHED*/ \ +} while (/*CONSTCOND*/0) +#else +#define SETERROR(err) \ +do { \ + /* external reference: error, and label bad */ \ + error = (err); \ + if (error == error) \ + goto bad; \ +} while (/*CONSTCOND*/0) +#endif + + +#define MATCH_FAMILY(x, y, w) \ + ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) +#define MATCH(x, y, w) \ + ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) + +#if 0 /*%< bind8 has its own version */ +char * +gai_strerror(ecode) + int ecode; +{ + if (ecode < 0 || ecode > EAI_MAX) + ecode = EAI_MAX; + return ai_errlist[ecode]; +} +#endif + +void +freeaddrinfo(ai) + struct addrinfo *ai; +{ + struct addrinfo *next; + + do { + next = ai->ai_next; + if (ai->ai_canonname) + free(ai->ai_canonname); + /* no need to free(ai->ai_addr) */ + free(ai); + ai = next; + } while (ai); +} + +static int +str_isnumber(p) + const char *p; +{ + char *ep; + + if (*p == '\0') + return NO; + ep = NULL; + errno = 0; + (void)strtoul(p, &ep, 10); + if (errno == 0 && ep && *ep == '\0') + return YES; + else + return NO; +} + +int +getaddrinfo(hostname, servname, hints, res) + const char *hostname, *servname; + const struct addrinfo *hints; + struct addrinfo **res; +{ + struct addrinfo sentinel; + struct addrinfo *cur; + int error = 0; + struct addrinfo ai, ai0, *afai = NULL; + struct addrinfo *pai; + const struct explore *ex; + + memset(&sentinel, 0, sizeof(sentinel)); + cur = &sentinel; + pai = &ai; + pai->ai_flags = 0; + pai->ai_family = PF_UNSPEC; + pai->ai_socktype = ANY; + pai->ai_protocol = ANY; +#if defined(sun) && defined(_SOCKLEN_T) && defined(__sparcv9) + /* + * clear _ai_pad to preserve binary + * compatibility with previously compiled 64-bit + * applications in a pre-SUSv3 environment by + * guaranteeing the upper 32-bits are empty. + */ + pai->_ai_pad = 0; +#endif + pai->ai_addrlen = 0; + pai->ai_canonname = NULL; + pai->ai_addr = NULL; + pai->ai_next = NULL; + + if (hostname == NULL && servname == NULL) + return EAI_NONAME; + if (hints) { + /* error check for hints */ + if (hints->ai_addrlen || hints->ai_canonname || + hints->ai_addr || hints->ai_next) + SETERROR(EAI_BADHINTS); /*%< xxx */ + if (hints->ai_flags & ~AI_MASK) + SETERROR(EAI_BADFLAGS); + switch (hints->ai_family) { + case PF_UNSPEC: + case PF_INET: + case PF_INET6: + break; + default: + SETERROR(EAI_FAMILY); + } + memcpy(pai, hints, sizeof(*pai)); + +#if defined(sun) && defined(_SOCKLEN_T) && defined(__sparcv9) + /* + * We need to clear _ai_pad to preserve binary + * compatibility. See prior comment. + */ + pai->_ai_pad = 0; +#endif + /* + * if both socktype/protocol are specified, check if they + * are meaningful combination. + */ + if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { + for (ex = explore; ex->e_af >= 0; ex++) { + if (pai->ai_family != ex->e_af) + continue; + if (ex->e_socktype == ANY) + continue; + if (ex->e_protocol == ANY) + continue; + if (pai->ai_socktype == ex->e_socktype && + pai->ai_protocol != ex->e_protocol) { + SETERROR(EAI_BADHINTS); + } + } + } + } + + /* + * post-2553: AI_ALL and AI_V4MAPPED are effective only against + * AF_INET6 query. They needs to be ignored if specified in other + * occassions. + */ + switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) { + case AI_V4MAPPED: + case AI_ALL | AI_V4MAPPED: + if (pai->ai_family != AF_INET6) + pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); + break; + case AI_ALL: +#if 1 + /* illegal */ + SETERROR(EAI_BADFLAGS); +#else + pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); + break; +#endif + } + + /* + * check for special cases. (1) numeric servname is disallowed if + * socktype/protocol are left unspecified. (2) servname is disallowed + * for raw and other inet{,6} sockets. + */ + if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) +#ifdef PF_INET6 + || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) +#endif + ) { + ai0 = *pai; /* backup *pai */ + + if (pai->ai_family == PF_UNSPEC) { +#ifdef PF_INET6 + pai->ai_family = PF_INET6; +#else + pai->ai_family = PF_INET; +#endif + } + error = get_portmatch(pai, servname); + if (error) + SETERROR(error); + + *pai = ai0; + } + + ai0 = *pai; + + /* NULL hostname, or numeric hostname */ + for (ex = explore; ex->e_af >= 0; ex++) { + *pai = ai0; + + if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) + continue; + if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) + continue; + if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) + continue; + + if (pai->ai_family == PF_UNSPEC) + pai->ai_family = ex->e_af; + if (pai->ai_socktype == ANY && ex->e_socktype != ANY) + pai->ai_socktype = ex->e_socktype; + if (pai->ai_protocol == ANY && ex->e_protocol != ANY) + pai->ai_protocol = ex->e_protocol; + + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + continue; + + if (hostname == NULL) { + /* + * filter out AFs that are not supported by the kernel + * XXX errno? + */ + if (!addrconfig(pai->ai_family)) + continue; + error = explore_null(pai, servname, &cur->ai_next); + } else + error = explore_numeric_scope(pai, hostname, servname, + &cur->ai_next); + + if (error) + goto free; + + while (cur && cur->ai_next) + cur = cur->ai_next; + } + + /* + * XXX + * If numreic representation of AF1 can be interpreted as FQDN + * representation of AF2, we need to think again about the code below. + */ + if (sentinel.ai_next) + goto good; + + if (pai->ai_flags & AI_NUMERICHOST) + SETERROR(EAI_NONAME); + if (hostname == NULL) + SETERROR(EAI_NONAME); + + /* + * hostname as alphabetical name. + * We'll make sure that + * - if returning addrinfo list is empty, return non-zero error + * value (already known one or EAI_NONAME). + * - otherwise, + * + if we haven't had any errors, return 0 (i.e. success). + * + if we've had an error, free the list and return the error. + * without any assumption on the behavior of explore_fqdn(). + */ + + /* first, try to query DNS for all possible address families. */ + *pai = ai0; + error = explore_fqdn(pai, hostname, servname, &afai); + if (error) { + if (afai != NULL) + freeaddrinfo(afai); + goto free; + } + if (afai == NULL) { + error = EAI_NONAME; /*%< we've had no errors. */ + goto free; + } + + /* + * we would like to prefer AF_INET6 than AF_INET, so we'll make an + * outer loop by AFs. + */ + for (ex = explore; ex->e_af >= 0; ex++) { + *pai = ai0; + + if (pai->ai_family == PF_UNSPEC) + pai->ai_family = ex->e_af; + + if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) + continue; + if (!MATCH(pai->ai_socktype, ex->e_socktype, + WILD_SOCKTYPE(ex))) { + continue; + } + if (!MATCH(pai->ai_protocol, ex->e_protocol, + WILD_PROTOCOL(ex))) { + continue; + } + +#ifdef AI_ADDRCONFIG + /* + * If AI_ADDRCONFIG is specified, check if we are + * expected to return the address family or not. + */ + if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && + !addrconfig(pai->ai_family)) + continue; +#endif + + if (pai->ai_family == PF_UNSPEC) + pai->ai_family = ex->e_af; + if (pai->ai_socktype == ANY && ex->e_socktype != ANY) + pai->ai_socktype = ex->e_socktype; + if (pai->ai_protocol == ANY && ex->e_protocol != ANY) + pai->ai_protocol = ex->e_protocol; + + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + continue; + + if ((error = explore_copy(pai, afai, &cur->ai_next)) != 0) { + freeaddrinfo(afai); + goto free; + } + + while (cur && cur->ai_next) + cur = cur->ai_next; + } + + freeaddrinfo(afai); /*%< afai must not be NULL at this point. */ + + if (sentinel.ai_next) { +good: + *res = sentinel.ai_next; + return(SUCCESS); + } else { + /* + * All the process succeeded, but we've had an empty list. + * This can happen if the given hints do not match our + * candidates. + */ + error = EAI_NONAME; + } + +free: +bad: + if (sentinel.ai_next) + freeaddrinfo(sentinel.ai_next); + *res = NULL; + return(error); +} + +/*% + * FQDN hostname, DNS lookup + */ +static int +explore_fqdn(pai, hostname, servname, res) + const struct addrinfo *pai; + const char *hostname; + const char *servname; + struct addrinfo **res; +{ + struct addrinfo *result; + struct addrinfo *cur; + struct net_data *net_data = init(); + struct irs_ho *ho; + int error = 0; + char tmp[NS_MAXDNAME]; + const char *cp; + + INSIST(res != NULL && *res == NULL); + + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + return(0); + + if (!net_data || !(ho = net_data->ho)) + return(0); +#if 0 /*%< XXX (notyet) */ + if (net_data->ho_stayopen && net_data->ho_last && + net_data->ho_last->h_addrtype == af) { + if (ns_samename(name, net_data->ho_last->h_name) == 1) + return (net_data->ho_last); + for (hap = net_data->ho_last->h_aliases; hap && *hap; hap++) + if (ns_samename(name, *hap) == 1) + return (net_data->ho_last); + } +#endif + if (!strchr(hostname, '.') && + (cp = res_hostalias(net_data->res, hostname, + tmp, sizeof(tmp)))) + hostname = cp; + result = (*ho->addrinfo)(ho, hostname, pai); + if (!net_data->ho_stayopen) { + (*ho->minimize)(ho); + } + if (result == NULL) { + int e = h_errno; + + switch(e) { + case NETDB_INTERNAL: + error = EAI_SYSTEM; + break; + case TRY_AGAIN: + error = EAI_AGAIN; + break; + case NO_RECOVERY: + error = EAI_FAIL; + break; + case HOST_NOT_FOUND: + case NO_DATA: + error = EAI_NONAME; + break; + default: + case NETDB_SUCCESS: /*%< should be impossible... */ + error = EAI_NONAME; + break; + } + goto free; + } + + for (cur = result; cur; cur = cur->ai_next) { + GET_PORT(cur, servname); /*%< XXX: redundant lookups... */ + /* canonname should already be filled. */ + } + + *res = result; + + return(0); + +free: + if (result) + freeaddrinfo(result); + return error; +} + +static int +explore_copy(pai, src0, res) + const struct addrinfo *pai; /*%< seed */ + const struct addrinfo *src0; /*%< source */ + struct addrinfo **res; +{ + int error; + struct addrinfo sentinel, *cur; + const struct addrinfo *src; + + error = 0; + sentinel.ai_next = NULL; + cur = &sentinel; + + for (src = src0; src != NULL; src = src->ai_next) { + if (src->ai_family != pai->ai_family) + continue; + + cur->ai_next = copy_ai(src); + if (!cur->ai_next) { + error = EAI_MEMORY; + goto fail; + } + + cur->ai_next->ai_socktype = pai->ai_socktype; + cur->ai_next->ai_protocol = pai->ai_protocol; + cur = cur->ai_next; + } + + *res = sentinel.ai_next; + return 0; + +fail: + freeaddrinfo(sentinel.ai_next); + return error; +} + +/*% + * hostname == NULL. + * passive socket -> anyaddr (0.0.0.0 or ::) + * non-passive socket -> localhost (127.0.0.1 or ::1) + */ +static int +explore_null(pai, servname, res) + const struct addrinfo *pai; + const char *servname; + struct addrinfo **res; +{ + const struct afd *afd; + struct addrinfo *cur; + struct addrinfo sentinel; + int error; + + *res = NULL; + sentinel.ai_next = NULL; + cur = &sentinel; + + afd = find_afd(pai->ai_family); + if (afd == NULL) + return 0; + + if (pai->ai_flags & AI_PASSIVE) { + GET_AI(cur->ai_next, afd, afd->a_addrany); + /* xxx meaningless? + * GET_CANONNAME(cur->ai_next, "anyaddr"); + */ + GET_PORT(cur->ai_next, servname); + } else { + GET_AI(cur->ai_next, afd, afd->a_loopback); + /* xxx meaningless? + * GET_CANONNAME(cur->ai_next, "localhost"); + */ + GET_PORT(cur->ai_next, servname); + } + cur = cur->ai_next; + + *res = sentinel.ai_next; + return 0; + +free: + if (sentinel.ai_next) + freeaddrinfo(sentinel.ai_next); + return error; +} + +/*% + * numeric hostname + */ +static int +explore_numeric(pai, hostname, servname, res) + const struct addrinfo *pai; + const char *hostname; + const char *servname; + struct addrinfo **res; +{ + const struct afd *afd; + struct addrinfo *cur; + struct addrinfo sentinel; + int error; + char pton[PTON_MAX]; + + *res = NULL; + sentinel.ai_next = NULL; + cur = &sentinel; + + afd = find_afd(pai->ai_family); + if (afd == NULL) + return 0; + + switch (afd->a_af) { +#if 0 /*X/Open spec*/ + case AF_INET: + if (inet_aton(hostname, (struct in_addr *)pton) == 1) { + if (pai->ai_family == afd->a_af || + pai->ai_family == PF_UNSPEC /*?*/) { + GET_AI(cur->ai_next, afd, pton); + GET_PORT(cur->ai_next, servname); + while (cur->ai_next) + cur = cur->ai_next; + } else + SETERROR(EAI_FAMILY); /*xxx*/ + } + break; +#endif + default: + if (inet_pton(afd->a_af, hostname, pton) == 1) { + if (pai->ai_family == afd->a_af || + pai->ai_family == PF_UNSPEC /*?*/) { + GET_AI(cur->ai_next, afd, pton); + GET_PORT(cur->ai_next, servname); + while (cur->ai_next) + cur = cur->ai_next; + } else + SETERROR(EAI_FAMILY); /*xxx*/ + } + break; + } + + *res = sentinel.ai_next; + return 0; + +free: +bad: + if (sentinel.ai_next) + freeaddrinfo(sentinel.ai_next); + return error; +} + +/*% + * numeric hostname with scope + */ +static int +explore_numeric_scope(pai, hostname, servname, res) + const struct addrinfo *pai; + const char *hostname; + const char *servname; + struct addrinfo **res; +{ +#ifndef SCOPE_DELIMITER + return explore_numeric(pai, hostname, servname, res); +#else + const struct afd *afd; + struct addrinfo *cur; + int error; + char *cp, *hostname2 = NULL, *scope, *addr; + struct sockaddr_in6 *sin6; + + afd = find_afd(pai->ai_family); + if (afd == NULL) + return 0; + + if (!afd->a_scoped) + return explore_numeric(pai, hostname, servname, res); + + cp = strchr(hostname, SCOPE_DELIMITER); + if (cp == NULL) + return explore_numeric(pai, hostname, servname, res); + + /* + * Handle special case of + */ + hostname2 = strdup(hostname); + if (hostname2 == NULL) + return EAI_MEMORY; + /* terminate at the delimiter */ + hostname2[cp - hostname] = '\0'; + addr = hostname2; + scope = cp + 1; + + error = explore_numeric(pai, addr, servname, res); + if (error == 0) { + u_int32_t scopeid = 0; + + for (cur = *res; cur; cur = cur->ai_next) { + if (cur->ai_family != AF_INET6) + continue; + sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; + if (!ip6_str2scopeid(scope, sin6, &scopeid)) { + free(hostname2); + return(EAI_NONAME); /*%< XXX: is return OK? */ + } +#ifdef HAVE_SIN6_SCOPE_ID + sin6->sin6_scope_id = scopeid; +#endif + } + } + + free(hostname2); + + return error; +#endif +} + +static int +get_canonname(pai, ai, str) + const struct addrinfo *pai; + struct addrinfo *ai; + const char *str; +{ + if ((pai->ai_flags & AI_CANONNAME) != 0) { + ai->ai_canonname = (char *)malloc(strlen(str) + 1); + if (ai->ai_canonname == NULL) + return EAI_MEMORY; + strcpy(ai->ai_canonname, str); + } + return 0; +} + +static struct addrinfo * +get_ai(pai, afd, addr) + const struct addrinfo *pai; + const struct afd *afd; + const char *addr; +{ + char *p; + struct addrinfo *ai; + + ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) + + (afd->a_socklen)); + if (ai == NULL) + return NULL; + + memcpy(ai, pai, sizeof(struct addrinfo)); + ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); + memset(ai->ai_addr, 0, (size_t)afd->a_socklen); +#ifdef HAVE_SA_LEN + ai->ai_addr->sa_len = afd->a_socklen; +#endif + ai->ai_addrlen = afd->a_socklen; + ai->ai_addr->sa_family = ai->ai_family = afd->a_af; + p = (char *)(void *)(ai->ai_addr); + memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); + return ai; +} + +/* XXX need to malloc() the same way we do from other functions! */ +static struct addrinfo * +copy_ai(pai) + const struct addrinfo *pai; +{ + struct addrinfo *ai; + size_t l; + + l = sizeof(*ai) + pai->ai_addrlen; + if ((ai = (struct addrinfo *)malloc(l)) == NULL) + return NULL; + memset(ai, 0, l); + memcpy(ai, pai, sizeof(*ai)); + ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); + memcpy(ai->ai_addr, pai->ai_addr, pai->ai_addrlen); + + if (pai->ai_canonname) { + l = strlen(pai->ai_canonname) + 1; + if ((ai->ai_canonname = malloc(l)) == NULL) { + free(ai); + return NULL; + } + strcpy(ai->ai_canonname, pai->ai_canonname); /* (checked) */ + } else { + /* just to make sure */ + ai->ai_canonname = NULL; + } + + ai->ai_next = NULL; + + return ai; +} + +static int +get_portmatch(const struct addrinfo *ai, const char *servname) { + + /* get_port does not touch first argument. when matchonly == 1. */ + /* LINTED const cast */ + return get_port((const struct addrinfo *)ai, servname, 1); +} + +static int +get_port(const struct addrinfo *ai, const char *servname, int matchonly) { + const char *proto; + struct servent *sp; + int port; + int allownumeric; + + if (servname == NULL) + return 0; + switch (ai->ai_family) { + case AF_INET: +#ifdef AF_INET6 + case AF_INET6: +#endif + break; + default: + return 0; + } + + switch (ai->ai_socktype) { + case SOCK_RAW: + return EAI_SERVICE; + case SOCK_DGRAM: + case SOCK_STREAM: + allownumeric = 1; + break; + case ANY: + switch (ai->ai_family) { + case AF_INET: +#ifdef AF_INET6 + case AF_INET6: +#endif + allownumeric = 1; + break; + default: + allownumeric = 0; + break; + } + break; + default: + return EAI_SOCKTYPE; + } + + if (str_isnumber(servname)) { + if (!allownumeric) + return EAI_SERVICE; + port = atoi(servname); + if (port < 0 || port > 65535) + return EAI_SERVICE; + port = htons(port); + } else { + switch (ai->ai_socktype) { + case SOCK_DGRAM: + proto = "udp"; + break; + case SOCK_STREAM: + proto = "tcp"; + break; + default: + proto = NULL; + break; + } + + if ((sp = getservbyname(servname, proto)) == NULL) + return EAI_SERVICE; + port = sp->s_port; + } + + if (!matchonly) { + switch (ai->ai_family) { + case AF_INET: + ((struct sockaddr_in *)(void *) + ai->ai_addr)->sin_port = port; + break; + case AF_INET6: + ((struct sockaddr_in6 *)(void *) + ai->ai_addr)->sin6_port = port; + break; + } + } + + return 0; +} + +static const struct afd * +find_afd(af) + int af; +{ + const struct afd *afd; + + if (af == PF_UNSPEC) + return NULL; + for (afd = afdl; afd->a_af; afd++) { + if (afd->a_af == af) + return afd; + } + return NULL; +} + +/*% + * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend + * will take care of it. + * the semantics of AI_ADDRCONFIG is not defined well. we are not sure + * if the code is right or not. + */ +static int +addrconfig(af) + int af; +{ + int s; + + /* XXX errno */ + s = socket(af, SOCK_DGRAM, 0); + if (s < 0) { + if (errno != EMFILE) + return 0; + } else + close(s); + return 1; +} + +/* convert a string to a scope identifier. XXX: IPv6 specific */ +static int +ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, + u_int32_t *scopeidp) +{ + u_int32_t scopeid; + u_long lscopeid; + struct in6_addr *a6 = &sin6->sin6_addr; + char *ep; + + /* empty scopeid portion is invalid */ + if (*scope == '\0') + return (0); + +#ifdef USE_IFNAMELINKID + if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6) || + IN6_IS_ADDR_MC_NODELOCAL(a6)) { + /* + * Using interface names as link indices can be allowed + * only when we can assume a one-to-one mappings between + * links and interfaces. See comments in getnameinfo.c. + */ + scopeid = if_nametoindex(scope); + if (scopeid == 0) + goto trynumeric; + *scopeidp = scopeid; + return (1); + } +#endif + + /* still unclear about literal, allow numeric only - placeholder */ + if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) + goto trynumeric; + if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) + goto trynumeric; + else + goto trynumeric; /*%< global */ + /* try to convert to a numeric id as a last resort */ +trynumeric: + errno = 0; + lscopeid = strtoul(scope, &ep, 10); + scopeid = lscopeid & 0xffffffff; + if (errno == 0 && ep && *ep == '\0' && scopeid == lscopeid) { + *scopeidp = scopeid; + return (1); + } else + return (0); +} + +struct addrinfo * +hostent2addrinfo(hp, pai) + struct hostent *hp; + const struct addrinfo *pai; +{ + int i, af, error = 0; + char **aplist = NULL, *ap; + struct addrinfo sentinel, *cur; + const struct afd *afd; + + af = hp->h_addrtype; + if (pai->ai_family != AF_UNSPEC && af != pai->ai_family) + return(NULL); + + afd = find_afd(af); + if (afd == NULL) + return(NULL); + + aplist = hp->h_addr_list; + + memset(&sentinel, 0, sizeof(sentinel)); + cur = &sentinel; + + for (i = 0; (ap = aplist[i]) != NULL; i++) { +#if 0 /*%< the trick seems too much */ + af = hp->h_addr_list; + if (af == AF_INET6 && + IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { + af = AF_INET; + ap = ap + sizeof(struct in6_addr) + - sizeof(struct in_addr); + } + afd = find_afd(af); + if (afd == NULL) + continue; +#endif /* 0 */ + + GET_AI(cur->ai_next, afd, ap); + + /* GET_PORT(cur->ai_next, servname); */ + if ((pai->ai_flags & AI_CANONNAME) != 0) { + /* + * RFC2553 says that ai_canonname will be set only for + * the first element. we do it for all the elements, + * just for convenience. + */ + GET_CANONNAME(cur->ai_next, hp->h_name); + } + while (cur->ai_next) /*%< no need to loop, actually. */ + cur = cur->ai_next; + continue; + + free: + if (cur->ai_next) + freeaddrinfo(cur->ai_next); + cur->ai_next = NULL; + /* continue, without tht pointer CUR advanced. */ + } + + return(sentinel.ai_next); +} + +struct addrinfo * +addr2addrinfo(pai, cp) + const struct addrinfo *pai; + const char *cp; +{ + const struct afd *afd; + + afd = find_afd(pai->ai_family); + if (afd == NULL) + return(NULL); + + return(get_ai(pai, afd, cp)); +} + +static struct net_data * +init() +{ + struct net_data *net_data; + + if (!(net_data = net_data_init(NULL))) + goto error; + if (!net_data->ho) { + net_data->ho = (*net_data->irs->ho_map)(net_data->irs); + if (!net_data->ho || !net_data->res) { +error: + errno = EIO; + if (net_data && net_data->res) + RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); + return (NULL); + } + + (*net_data->ho->res_set)(net_data->ho, net_data->res, NULL); + } + + return (net_data); +} diff --git a/contrib/bind-9.5.2/lib/bind/irs/getgrent.c b/contrib/bind-9.5.2/lib/bind/irs/getgrent.c new file mode 100644 index 0000000000..e6c6c42147 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/getgrent.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: getgrent.c,v 1.5 2005/04/27 04:56:24 sra Exp $"; +#endif + +/* Imports */ + +#include "port_before.h" + +#if !defined(WANT_IRS_GR) || defined(__BIND_NOSTATIC) +static int __bind_irs_gr_unneeded; +#else + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "port_after.h" + +#include "irs_data.h" + +/* Forward */ + +static struct net_data *init(void); +void endgrent(void); + +/* Public */ + +struct group * +getgrent() { + struct net_data *net_data = init(); + + return (getgrent_p(net_data)); +} + +struct group * +getgrnam(const char *name) { + struct net_data *net_data = init(); + + return (getgrnam_p(name, net_data)); +} + +struct group * +getgrgid(gid_t gid) { + struct net_data *net_data = init(); + + return (getgrgid_p(gid, net_data)); +} + +int +setgroupent(int stayopen) { + struct net_data *net_data = init(); + + return (setgroupent_p(stayopen, net_data)); +} + +#ifdef SETGRENT_VOID +void +setgrent(void) { + struct net_data *net_data = init(); + + setgrent_p(net_data); +} +#else +int +setgrent(void) { + struct net_data *net_data = init(); + + return (setgrent_p(net_data)); +} +#endif /* SETGRENT_VOID */ + +void +endgrent() { + struct net_data *net_data = init(); + + endgrent_p(net_data); +} + +int +getgrouplist(GETGROUPLIST_ARGS) { + struct net_data *net_data = init(); + + return (getgrouplist_p(name, basegid, groups, ngroups, net_data)); +} + +/* Shared private. */ + +struct group * +getgrent_p(struct net_data *net_data) { + struct irs_gr *gr; + + if (!net_data || !(gr = net_data->gr)) + return (NULL); + net_data->gr_last = (*gr->next)(gr); + return (net_data->gr_last); +} + +struct group * +getgrnam_p(const char *name, struct net_data *net_data) { + struct irs_gr *gr; + + if (!net_data || !(gr = net_data->gr)) + return (NULL); + if (net_data->gr_stayopen && net_data->gr_last && + !strcmp(net_data->gr_last->gr_name, name)) + return (net_data->gr_last); + net_data->gr_last = (*gr->byname)(gr, name); + if (!net_data->gr_stayopen) + endgrent(); + return (net_data->gr_last); +} + +struct group * +getgrgid_p(gid_t gid, struct net_data *net_data) { + struct irs_gr *gr; + + if (!net_data || !(gr = net_data->gr)) + return (NULL); + if (net_data->gr_stayopen && net_data->gr_last && + (gid_t)net_data->gr_last->gr_gid == gid) + return (net_data->gr_last); + net_data->gr_last = (*gr->bygid)(gr, gid); + if (!net_data->gr_stayopen) + endgrent(); + return (net_data->gr_last); +} + +int +setgroupent_p(int stayopen, struct net_data *net_data) { + struct irs_gr *gr; + + if (!net_data || !(gr = net_data->gr)) + return (0); + (*gr->rewind)(gr); + net_data->gr_stayopen = (stayopen != 0); + if (stayopen == 0) + net_data_minimize(net_data); + return (1); +} + +#ifdef SETGRENT_VOID +void +setgrent_p(struct net_data *net_data) { + (void)setgroupent_p(0, net_data); +} +#else +int +setgrent_p(struct net_data *net_data) { + return (setgroupent_p(0, net_data)); +} +#endif /* SETGRENT_VOID */ + +void +endgrent_p(struct net_data *net_data) { + struct irs_gr *gr; + + if ((net_data != NULL) && ((gr = net_data->gr) != NULL)) + (*gr->minimize)(gr); +} + +int +getgrouplist_p(const char *name, gid_t basegid, gid_t *groups, int *ngroups, + struct net_data *net_data) { + struct irs_gr *gr; + + if (!net_data || !(gr = net_data->gr)) { + *ngroups = 0; + return (-1); + } + return ((*gr->list)(gr, name, basegid, groups, ngroups)); +} + +/* Private */ + +static struct net_data * +init() { + struct net_data *net_data; + + if (!(net_data = net_data_init(NULL))) + goto error; + if (!net_data->gr) { + net_data->gr = (*net_data->irs->gr_map)(net_data->irs); + + if (!net_data->gr || !net_data->res) { + error: + errno = EIO; + return (NULL); + } + (*net_data->gr->res_set)(net_data->gr, net_data->res, + NULL); + } + + return (net_data); +} + +#endif /* WANT_IRS_GR */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/getgrent_r.c b/contrib/bind-9.5.2/lib/bind/irs/getgrent_r.c new file mode 100644 index 0000000000..eb9c7947cd --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/getgrent_r.c @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1998-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: getgrent_r.c,v 1.7 2005/04/27 04:56:24 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#if !defined(_REENTRANT) || !defined(DO_PTHREADS) || !defined(WANT_IRS_PW) + static int getgrent_r_not_required = 0; +#else +#include +#include +#include +#include +#if (defined(POSIX_GETGRNAM_R) || defined(POSIX_GETGRGID_R)) && \ + defined(_POSIX_PTHREAD_SEMANTICS) + /* turn off solaris remapping in */ +#define _UNIX95 +#undef _POSIX_PTHREAD_SEMANTICS +#include +#define _POSIX_PTHREAD_SEMANTICS 1 +#else +#include +#endif +#include +#include + +#ifdef GROUP_R_RETURN + +static int +copy_group(struct group *, struct group *, char *buf, int buflen); + +/* POSIX 1003.1c */ +#ifdef POSIX_GETGRNAM_R +int +__posix_getgrnam_r(const char *name, struct group *gptr, + char *buf, int buflen, struct group **result) { +#else +int +getgrnam_r(const char *name, struct group *gptr, + char *buf, size_t buflen, struct group **result) { +#endif + struct group *ge = getgrnam(name); + int res; + + if (ge == NULL) { + *result = NULL; + return (0); + } + + res = copy_group(ge, gptr, buf, buflen); + *result = res ? NULL : gptr; + return (res); +} + +#ifdef POSIX_GETGRNAM_R +struct group * +getgrnam_r(const char *name, struct group *gptr, + char *buf, int buflen) { + struct group *ge = getgrnam(name); + int res; + + if (ge == NULL) + return (NULL); + res = copy_group(ge, gptr, buf, buflen); + return (res ? NULL : gptr); +} +#endif /* POSIX_GETGRNAM_R */ + +/* POSIX 1003.1c */ +#ifdef POSIX_GETGRGID_R +int +__posix_getgrgid_r(gid_t gid, struct group *gptr, + char *buf, int buflen, struct group **result) { +#else /* POSIX_GETGRGID_R */ +int +getgrgid_r(gid_t gid, struct group *gptr, + char *buf, size_t buflen, struct group **result) { +#endif /* POSIX_GETGRGID_R */ + struct group *ge = getgrgid(gid); + int res; + + if (ge == NULL) { + *result = NULL; + return (0); + } + + res = copy_group(ge, gptr, buf, buflen); + *result = res ? NULL : gptr; + return (res); +} + +#ifdef POSIX_GETGRGID_R +struct group * +getgrgid_r(gid_t gid, struct group *gptr, + char *buf, int buflen) { + struct group *ge = getgrgid(gid); + int res; + + if (ge == NULL) + return (NULL); + + res = copy_group(ge, gptr, buf, buflen); + return (res ? NULL : gptr); +} +#endif + +/*% + * These assume a single context is in operation per thread. + * If this is not the case we will need to call irs directly + * rather than through the base functions. + */ + +GROUP_R_RETURN +getgrent_r(struct group *gptr, GROUP_R_ARGS) { + struct group *ge = getgrent(); + int res; + + if (ge == NULL) { + return (GROUP_R_BAD); + } + + res = copy_group(ge, gptr, buf, buflen); + return (res ? GROUP_R_BAD : GROUP_R_OK); +} + +GROUP_R_SET_RETURN +setgrent_r(GROUP_R_ENT_ARGS) { + + setgrent(); +#ifdef GROUP_R_SET_RESULT + return (GROUP_R_SET_RESULT); +#endif +} + +GROUP_R_END_RETURN +endgrent_r(GROUP_R_ENT_ARGS) { + + endgrent(); + GROUP_R_END_RESULT(GROUP_R_OK); +} + + +#if 0 + /* XXX irs does not have a fgetgrent() */ +GROUP_R_RETURN +fgetgrent_r(FILE *f, struct group *gptr, GROUP_R_ARGS) { + struct group *ge = fgetgrent(f); + int res; + + if (ge == NULL) + return (GROUP_R_BAD); + + res = copy_group(ge, gptr, buf, buflen); + return (res ? GROUP_R_BAD : GROUP_R_OK); +} +#endif + +/* Private */ + +static int +copy_group(struct group *ge, struct group *gptr, char *buf, int buflen) { + char *cp; + int i, n; + int numptr, len; + + /* Find out the amount of space required to store the answer. */ + numptr = 1; /*%< NULL ptr */ + len = (char *)ALIGN(buf) - buf; + for (i = 0; ge->gr_mem[i]; i++, numptr++) { + len += strlen(ge->gr_mem[i]) + 1; + } + len += strlen(ge->gr_name) + 1; + len += strlen(ge->gr_passwd) + 1; + len += numptr * sizeof(char*); + + if (len > buflen) { + errno = ERANGE; + return (ERANGE); + } + + /* copy group id */ + gptr->gr_gid = ge->gr_gid; + + cp = (char *)ALIGN(buf) + numptr * sizeof(char *); + + /* copy official name */ + n = strlen(ge->gr_name) + 1; + strcpy(cp, ge->gr_name); + gptr->gr_name = cp; + cp += n; + + /* copy member list */ + gptr->gr_mem = (char **)ALIGN(buf); + for (i = 0 ; ge->gr_mem[i]; i++) { + n = strlen(ge->gr_mem[i]) + 1; + strcpy(cp, ge->gr_mem[i]); + gptr->gr_mem[i] = cp; + cp += n; + } + gptr->gr_mem[i] = NULL; + + /* copy password */ + n = strlen(ge->gr_passwd) + 1; + strcpy(cp, ge->gr_passwd); + gptr->gr_passwd = cp; + cp += n; + + return (0); +} +#else /* GROUP_R_RETURN */ + static int getgrent_r_unknown_system = 0; +#endif /* GROUP_R_RETURN */ +#endif /* !def(_REENTRANT) || !def(DO_PTHREADS) || !def(WANT_IRS_PW) */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/gethostent.c b/contrib/bind-9.5.2/lib/bind/irs/gethostent.c new file mode 100644 index 0000000000..d8c9e24b1f --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/gethostent.c @@ -0,0 +1,1070 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: gethostent.c,v 1.8 2006/01/10 05:06:00 marka Exp $"; +#endif + +/* Imports */ + +#include "port_before.h" + +#if !defined(__BIND_NOSTATIC) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "irs_data.h" + +/* Definitions */ + +struct pvt { + char * aliases[1]; + char * addrs[2]; + char addr[NS_IN6ADDRSZ]; + char name[NS_MAXDNAME + 1]; + struct hostent host; +}; + +/* Forward */ + +static struct net_data *init(void); +static void freepvt(struct net_data *); +static struct hostent *fakeaddr(const char *, int, struct net_data *); + + +/* Public */ + +struct hostent * +gethostbyname(const char *name) { + struct net_data *net_data = init(); + + return (gethostbyname_p(name, net_data)); +} + +struct hostent * +gethostbyname2(const char *name, int af) { + struct net_data *net_data = init(); + + return (gethostbyname2_p(name, af, net_data)); +} + +struct hostent * +gethostbyaddr(const char *addr, int len, int af) { + struct net_data *net_data = init(); + + return (gethostbyaddr_p(addr, len, af, net_data)); +} + +struct hostent * +gethostent() { + struct net_data *net_data = init(); + + return (gethostent_p(net_data)); +} + +void +sethostent(int stayopen) { + struct net_data *net_data = init(); + sethostent_p(stayopen, net_data); +} + + +void +endhostent() { + struct net_data *net_data = init(); + endhostent_p(net_data); +} + +/* Shared private. */ + +struct hostent * +gethostbyname_p(const char *name, struct net_data *net_data) { + struct hostent *hp; + + if (!net_data) + return (NULL); + + if (net_data->res->options & RES_USE_INET6) { + hp = gethostbyname2_p(name, AF_INET6, net_data); + if (hp) + return (hp); + } + return (gethostbyname2_p(name, AF_INET, net_data)); +} + +struct hostent * +gethostbyname2_p(const char *name, int af, struct net_data *net_data) { + struct irs_ho *ho; + char tmp[NS_MAXDNAME]; + struct hostent *hp; + const char *cp; + char **hap; + + if (!net_data || !(ho = net_data->ho)) + return (NULL); + if (net_data->ho_stayopen && net_data->ho_last && + net_data->ho_last->h_addrtype == af) { + if (ns_samename(name, net_data->ho_last->h_name) == 1) + return (net_data->ho_last); + for (hap = net_data->ho_last->h_aliases; hap && *hap; hap++) + if (ns_samename(name, *hap) == 1) + return (net_data->ho_last); + } + if (!strchr(name, '.') && (cp = res_hostalias(net_data->res, name, + tmp, sizeof tmp))) + name = cp; + if ((hp = fakeaddr(name, af, net_data)) != NULL) + return (hp); + net_data->ho_last = (*ho->byname2)(ho, name, af); + if (!net_data->ho_stayopen) + endhostent(); + return (net_data->ho_last); +} + +struct hostent * +gethostbyaddr_p(const char *addr, int len, int af, struct net_data *net_data) { + struct irs_ho *ho; + char **hap; + + if (!net_data || !(ho = net_data->ho)) + return (NULL); + if (net_data->ho_stayopen && net_data->ho_last && + net_data->ho_last->h_length == len) + for (hap = net_data->ho_last->h_addr_list; + hap && *hap; + hap++) + if (!memcmp(addr, *hap, len)) + return (net_data->ho_last); + net_data->ho_last = (*ho->byaddr)(ho, addr, len, af); + if (!net_data->ho_stayopen) + endhostent(); + return (net_data->ho_last); +} + + +struct hostent * +gethostent_p(struct net_data *net_data) { + struct irs_ho *ho; + struct hostent *hp; + + if (!net_data || !(ho = net_data->ho)) + return (NULL); + while ((hp = (*ho->next)(ho)) != NULL && + hp->h_addrtype == AF_INET6 && + (net_data->res->options & RES_USE_INET6) == 0U) + continue; + net_data->ho_last = hp; + return (net_data->ho_last); +} + + +void +sethostent_p(int stayopen, struct net_data *net_data) { + struct irs_ho *ho; + + if (!net_data || !(ho = net_data->ho)) + return; + freepvt(net_data); + (*ho->rewind)(ho); + net_data->ho_stayopen = (stayopen != 0); + if (stayopen == 0) + net_data_minimize(net_data); +} + +void +endhostent_p(struct net_data *net_data) { + struct irs_ho *ho; + + if ((net_data != NULL) && ((ho = net_data->ho) != NULL)) + (*ho->minimize)(ho); +} + +#ifndef IN6_IS_ADDR_V4COMPAT +static const unsigned char in6addr_compat[12] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +#define IN6_IS_ADDR_V4COMPAT(x) (!memcmp((x)->s6_addr, in6addr_compat, 12) && \ + ((x)->s6_addr[12] != 0 || \ + (x)->s6_addr[13] != 0 || \ + (x)->s6_addr[14] != 0 || \ + ((x)->s6_addr[15] != 0 && \ + (x)->s6_addr[15] != 1))) +#endif +#ifndef IN6_IS_ADDR_V4MAPPED +#define IN6_IS_ADDR_V4MAPPED(x) (!memcmp((x)->s6_addr, in6addr_mapped, 12)) +#endif + +static const unsigned char in6addr_mapped[12] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; + +static int scan_interfaces(int *, int *); +static struct hostent *copyandmerge(struct hostent *, struct hostent *, int, int *); + +/*% + * Public functions + */ + +/*% + * AI_V4MAPPED + AF_INET6 + * If no IPv6 address then a query for IPv4 and map returned values. + * + * AI_ALL + AI_V4MAPPED + AF_INET6 + * Return IPv6 and IPv4 mapped. + * + * AI_ADDRCONFIG + * Only return IPv6 / IPv4 address if there is an interface of that + * type active. + */ + +struct hostent * +getipnodebyname(const char *name, int af, int flags, int *error_num) { + int have_v4 = 1, have_v6 = 1; + struct in_addr in4; + struct in6_addr in6; + struct hostent he, *he1 = NULL, *he2 = NULL, *he3; + int v4 = 0, v6 = 0; + struct net_data *net_data = init(); + u_long options; + int tmp_err; + + if (net_data == NULL) { + *error_num = NO_RECOVERY; + return (NULL); + } + + /* If we care about active interfaces then check. */ + if ((flags & AI_ADDRCONFIG) != 0) + if (scan_interfaces(&have_v4, &have_v6) == -1) { + *error_num = NO_RECOVERY; + return (NULL); + } + + /* Check for literal address. */ + if ((v4 = inet_pton(AF_INET, name, &in4)) != 1) + v6 = inet_pton(AF_INET6, name, &in6); + + /* Impossible combination? */ + + if ((af == AF_INET6 && (flags & AI_V4MAPPED) == 0 && v4 == 1) || + (af == AF_INET && v6 == 1) || + (have_v4 == 0 && v4 == 1) || + (have_v6 == 0 && v6 == 1) || + (have_v4 == 0 && af == AF_INET) || + (have_v6 == 0 && af == AF_INET6)) { + *error_num = HOST_NOT_FOUND; + return (NULL); + } + + /* Literal address? */ + if (v4 == 1 || v6 == 1) { + char *addr_list[2]; + char *aliases[1]; + + DE_CONST(name, he.h_name); + he.h_addr_list = addr_list; + he.h_addr_list[0] = (v4 == 1) ? (char *)&in4 : (char *)&in6; + he.h_addr_list[1] = NULL; + he.h_aliases = aliases; + he.h_aliases[0] = NULL; + he.h_length = (v4 == 1) ? INADDRSZ : IN6ADDRSZ; + he.h_addrtype = (v4 == 1) ? AF_INET : AF_INET6; + return (copyandmerge(&he, NULL, af, error_num)); + } + + options = net_data->res->options; + net_data->res->options &= ~RES_USE_INET6; + + tmp_err = NO_RECOVERY; + if (have_v6 && af == AF_INET6) { + he2 = gethostbyname2_p(name, AF_INET6, net_data); + if (he2 != NULL) { + he1 = copyandmerge(he2, NULL, af, error_num); + if (he1 == NULL) + return (NULL); + he2 = NULL; + } else { + tmp_err = net_data->res->res_h_errno; + } + } + + if (have_v4 && + ((af == AF_INET) || + (af == AF_INET6 && (flags & AI_V4MAPPED) != 0 && + (he1 == NULL || (flags & AI_ALL) != 0)))) { + he2 = gethostbyname2_p(name, AF_INET, net_data); + if (he1 == NULL && he2 == NULL) { + *error_num = net_data->res->res_h_errno; + return (NULL); + } + } else + *error_num = tmp_err; + + net_data->res->options = options; + + he3 = copyandmerge(he1, he2, af, error_num); + + if (he1 != NULL) + freehostent(he1); + return (he3); +} + +struct hostent * +getipnodebyaddr(const void *src, size_t len, int af, int *error_num) { + struct hostent *he1, *he2; + struct net_data *net_data = init(); + + /* Sanity Checks. */ + if (src == NULL) { + *error_num = NO_RECOVERY; + return (NULL); + } + + switch (af) { + case AF_INET: + if (len != (size_t)INADDRSZ) { + *error_num = NO_RECOVERY; + return (NULL); + } + break; + case AF_INET6: + if (len != (size_t)IN6ADDRSZ) { + *error_num = NO_RECOVERY; + return (NULL); + } + break; + default: + *error_num = NO_RECOVERY; + return (NULL); + } + + /* + * Lookup IPv4 and IPv4 mapped/compatible addresses + */ + if ((af == AF_INET6 && + IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)src)) || + (af == AF_INET6 && + IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src)) || + (af == AF_INET)) { + const char *cp = src; + + if (af == AF_INET6) + cp += 12; + he1 = gethostbyaddr_p(cp, 4, AF_INET, net_data); + if (he1 == NULL) { + *error_num = net_data->res->res_h_errno; + return (NULL); + } + he2 = copyandmerge(he1, NULL, af, error_num); + if (he2 == NULL) + return (NULL); + /* + * Restore original address if mapped/compatible. + */ + if (af == AF_INET6) + memcpy(he1->h_addr, src, len); + return (he2); + } + + /* + * Lookup IPv6 address. + */ + if (memcmp((const struct in6_addr *)src, &in6addr_any, 16) == 0) { + *error_num = HOST_NOT_FOUND; + return (NULL); + } + + he1 = gethostbyaddr_p(src, 16, AF_INET6, net_data); + if (he1 == NULL) { + *error_num = net_data->res->res_h_errno; + return (NULL); + } + return (copyandmerge(he1, NULL, af, error_num)); +} + +void +freehostent(struct hostent *he) { + char **cpp; + int names = 1; + int addresses = 1; + + memput(he->h_name, strlen(he->h_name) + 1); + + cpp = he->h_addr_list; + while (*cpp != NULL) { + memput(*cpp, (he->h_addrtype == AF_INET) ? + INADDRSZ : IN6ADDRSZ); + *cpp = NULL; + cpp++; + addresses++; + } + + cpp = he->h_aliases; + while (*cpp != NULL) { + memput(*cpp, strlen(*cpp) + 1); + cpp++; + names++; + } + + memput(he->h_aliases, sizeof(char *) * (names)); + memput(he->h_addr_list, sizeof(char *) * (addresses)); + memput(he, sizeof *he); +} + +/*% + * Private + */ + +/*% + * Scan the interface table and set have_v4 and have_v6 depending + * upon whether there are IPv4 and IPv6 interface addresses. + * + * Returns: + * 0 on success + * -1 on failure. + */ + +#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \ + !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF) + +#ifdef __hpux +#define lifc_len iflc_len +#define lifc_buf iflc_buf +#define lifc_req iflc_req +#define LIFCONF if_laddrconf +#else +#define SETFAMILYFLAGS +#define LIFCONF lifconf +#endif + +#ifdef __hpux +#define lifr_addr iflr_addr +#define lifr_name iflr_name +#define lifr_dstaddr iflr_dstaddr +#define lifr_flags iflr_flags +#define ss_family sa_family +#define LIFREQ if_laddrreq +#else +#define LIFREQ lifreq +#endif + +static void +scan_interfaces6(int *have_v4, int *have_v6) { + struct LIFCONF lifc; + struct LIFREQ lifreq; + struct in_addr in4; + struct in6_addr in6; + char *buf = NULL, *cp, *cplim; + static unsigned int bufsiz = 4095; + int s, cpsize, n; + + /* Get interface list from system. */ + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) + goto cleanup; + + /* + * Grow buffer until large enough to contain all interface + * descriptions. + */ + for (;;) { + buf = memget(bufsiz); + if (buf == NULL) + goto cleanup; +#ifdef SETFAMILYFLAGS + lifc.lifc_family = AF_UNSPEC; /*%< request all families */ + lifc.lifc_flags = 0; +#endif + lifc.lifc_len = bufsiz; + lifc.lifc_buf = buf; + if ((n = ioctl(s, SIOCGLIFCONF, (char *)&lifc)) != -1) { + /* + * Some OS's just return what will fit rather + * than set EINVAL if the buffer is too small + * to fit all the interfaces in. If + * lifc.lifc_len is too near to the end of the + * buffer we will grow it just in case and + * retry. + */ + if (lifc.lifc_len + 2 * sizeof(lifreq) < bufsiz) + break; + } + if ((n == -1) && errno != EINVAL) + goto cleanup; + + if (bufsiz > 1000000) + goto cleanup; + + memput(buf, bufsiz); + bufsiz += 4096; + } + + /* Parse system's interface list. */ + cplim = buf + lifc.lifc_len; /*%< skip over if's with big ifr_addr's */ + for (cp = buf; + (*have_v4 == 0 || *have_v6 == 0) && cp < cplim; + cp += cpsize) { + memcpy(&lifreq, cp, sizeof lifreq); +#ifdef HAVE_SA_LEN +#ifdef FIX_ZERO_SA_LEN + if (lifreq.lifr_addr.sa_len == 0) + lifreq.lifr_addr.sa_len = 16; +#endif +#ifdef HAVE_MINIMUM_IFREQ + cpsize = sizeof lifreq; + if (lifreq.lifr_addr.sa_len > sizeof (struct sockaddr)) + cpsize += (int)lifreq.lifr_addr.sa_len - + (int)(sizeof (struct sockaddr)); +#else + cpsize = sizeof lifreq.lifr_name + lifreq.lifr_addr.sa_len; +#endif /* HAVE_MINIMUM_IFREQ */ +#elif defined SIOCGIFCONF_ADDR + cpsize = sizeof lifreq; +#else + cpsize = sizeof lifreq.lifr_name; + /* XXX maybe this should be a hard error? */ + if (ioctl(s, SIOCGLIFADDR, (char *)&lifreq) < 0) + continue; +#endif + switch (lifreq.lifr_addr.ss_family) { + case AF_INET: + if (*have_v4 == 0) { + memcpy(&in4, + &((struct sockaddr_in *) + &lifreq.lifr_addr)->sin_addr, + sizeof in4); + if (in4.s_addr == INADDR_ANY) + break; + n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq); + if (n < 0) + break; + if ((lifreq.lifr_flags & IFF_UP) == 0) + break; + *have_v4 = 1; + } + break; + case AF_INET6: + if (*have_v6 == 0) { + memcpy(&in6, + &((struct sockaddr_in6 *) + &lifreq.lifr_addr)->sin6_addr, sizeof in6); + if (memcmp(&in6, &in6addr_any, sizeof in6) == 0) + break; + n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq); + if (n < 0) + break; + if ((lifreq.lifr_flags & IFF_UP) == 0) + break; + *have_v6 = 1; + } + break; + } + } + if (buf != NULL) + memput(buf, bufsiz); + close(s); + /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */ + return; + cleanup: + if (buf != NULL) + memput(buf, bufsiz); + if (s != -1) + close(s); + /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */ + return; +} +#endif + +#if ( defined(__linux__) || defined(__linux) || defined(LINUX) ) +#ifndef IF_NAMESIZE +# ifdef IFNAMSIZ +# define IF_NAMESIZE IFNAMSIZ +# else +# define IF_NAMESIZE 16 +# endif +#endif +static void +scan_linux6(int *have_v6) { + FILE *proc = NULL; + char address[33]; + char name[IF_NAMESIZE+1]; + int ifindex, prefix, flag3, flag4; + + proc = fopen("/proc/net/if_inet6", "r"); + if (proc == NULL) + return; + + if (fscanf(proc, "%32[a-f0-9] %x %x %x %x %16s\n", + address, &ifindex, &prefix, &flag3, &flag4, name) == 6) + *have_v6 = 1; + fclose(proc); + return; +} +#endif + +static int +scan_interfaces(int *have_v4, int *have_v6) { + struct ifconf ifc; + union { + char _pad[256]; /*%< leave space for IPv6 addresses */ + struct ifreq ifreq; + } u; + struct in_addr in4; + struct in6_addr in6; + char *buf = NULL, *cp, *cplim; + static unsigned int bufsiz = 4095; + int s, n; + size_t cpsize; + + /* Set to zero. Used as loop terminators below. */ + *have_v4 = *have_v6 = 0; + +#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \ + !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF) + /* + * Try to scan the interfaces using IPv6 ioctls(). + */ + scan_interfaces6(have_v4, have_v6); + if (*have_v4 != 0 && *have_v6 != 0) + return (0); +#endif +#ifdef __linux + scan_linux6(have_v6); +#endif + + /* Get interface list from system. */ + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) + goto err_ret; + + /* + * Grow buffer until large enough to contain all interface + * descriptions. + */ + for (;;) { + buf = memget(bufsiz); + if (buf == NULL) + goto err_ret; + ifc.ifc_len = bufsiz; + ifc.ifc_buf = buf; +#ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF + /* + * This is a fix for IRIX OS in which the call to ioctl with + * the flag SIOCGIFCONF may not return an entry for all the + * interfaces like most flavors of Unix. + */ + if (emul_ioctl(&ifc) >= 0) + break; +#else + if ((n = ioctl(s, SIOCGIFCONF, (char *)&ifc)) != -1) { + /* + * Some OS's just return what will fit rather + * than set EINVAL if the buffer is too small + * to fit all the interfaces in. If + * ifc.ifc_len is too near to the end of the + * buffer we will grow it just in case and + * retry. + */ + if (ifc.ifc_len + 2 * sizeof(u.ifreq) < bufsiz) + break; + } +#endif + if ((n == -1) && errno != EINVAL) + goto err_ret; + + if (bufsiz > 1000000) + goto err_ret; + + memput(buf, bufsiz); + bufsiz += 4096; + } + + /* Parse system's interface list. */ + cplim = buf + ifc.ifc_len; /*%< skip over if's with big ifr_addr's */ + for (cp = buf; + (*have_v4 == 0 || *have_v6 == 0) && cp < cplim; + cp += cpsize) { + memcpy(&u.ifreq, cp, sizeof u.ifreq); +#ifdef HAVE_SA_LEN +#ifdef FIX_ZERO_SA_LEN + if (u.ifreq.ifr_addr.sa_len == 0) + u.ifreq.ifr_addr.sa_len = 16; +#endif +#ifdef HAVE_MINIMUM_IFREQ + cpsize = sizeof u.ifreq; + if (u.ifreq.ifr_addr.sa_len > sizeof (struct sockaddr)) + cpsize += (int)u.ifreq.ifr_addr.sa_len - + (int)(sizeof (struct sockaddr)); +#else + cpsize = sizeof u.ifreq.ifr_name + u.ifreq.ifr_addr.sa_len; +#endif /* HAVE_MINIMUM_IFREQ */ + if (cpsize > sizeof u.ifreq && cpsize <= sizeof u) + memcpy(&u.ifreq, cp, cpsize); +#elif defined SIOCGIFCONF_ADDR + cpsize = sizeof u.ifreq; +#else + cpsize = sizeof u.ifreq.ifr_name; + /* XXX maybe this should be a hard error? */ + if (ioctl(s, SIOCGIFADDR, (char *)&u.ifreq) < 0) + continue; +#endif + switch (u.ifreq.ifr_addr.sa_family) { + case AF_INET: + if (*have_v4 == 0) { + memcpy(&in4, + &((struct sockaddr_in *) + &u.ifreq.ifr_addr)->sin_addr, + sizeof in4); + if (in4.s_addr == INADDR_ANY) + break; + n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq); + if (n < 0) + break; + if ((u.ifreq.ifr_flags & IFF_UP) == 0) + break; + *have_v4 = 1; + } + break; + case AF_INET6: + if (*have_v6 == 0) { + memcpy(&in6, + &((struct sockaddr_in6 *) + &u.ifreq.ifr_addr)->sin6_addr, + sizeof in6); + if (memcmp(&in6, &in6addr_any, sizeof in6) == 0) + break; + n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq); + if (n < 0) + break; + if ((u.ifreq.ifr_flags & IFF_UP) == 0) + break; + *have_v6 = 1; + } + break; + } + } + if (buf != NULL) + memput(buf, bufsiz); + close(s); + /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */ + return (0); + err_ret: + if (buf != NULL) + memput(buf, bufsiz); + if (s != -1) + close(s); + /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */ + return (-1); +} + +static struct hostent * +copyandmerge(struct hostent *he1, struct hostent *he2, int af, int *error_num) { + struct hostent *he = NULL; + int addresses = 1; /*%< NULL terminator */ + int names = 1; /*%< NULL terminator */ + int len = 0; + char **cpp, **npp; + + /* + * Work out array sizes; + */ + if (he1 != NULL) { + cpp = he1->h_addr_list; + while (*cpp != NULL) { + addresses++; + cpp++; + } + cpp = he1->h_aliases; + while (*cpp != NULL) { + names++; + cpp++; + } + } + + if (he2 != NULL) { + cpp = he2->h_addr_list; + while (*cpp != NULL) { + addresses++; + cpp++; + } + if (he1 == NULL) { + cpp = he2->h_aliases; + while (*cpp != NULL) { + names++; + cpp++; + } + } + } + + if (addresses == 1) { + *error_num = NO_ADDRESS; + return (NULL); + } + + he = memget(sizeof *he); + if (he == NULL) + goto no_recovery; + + he->h_addr_list = memget(sizeof(char *) * (addresses)); + if (he->h_addr_list == NULL) + goto cleanup0; + memset(he->h_addr_list, 0, sizeof(char *) * (addresses)); + + /* copy addresses */ + npp = he->h_addr_list; + if (he1 != NULL) { + cpp = he1->h_addr_list; + while (*cpp != NULL) { + *npp = memget((af == AF_INET) ? INADDRSZ : IN6ADDRSZ); + if (*npp == NULL) + goto cleanup1; + /* convert to mapped if required */ + if (af == AF_INET6 && he1->h_addrtype == AF_INET) { + memcpy(*npp, in6addr_mapped, + sizeof in6addr_mapped); + memcpy(*npp + sizeof in6addr_mapped, *cpp, + INADDRSZ); + } else { + memcpy(*npp, *cpp, + (af == AF_INET) ? INADDRSZ : IN6ADDRSZ); + } + cpp++; + npp++; + } + } + + if (he2 != NULL) { + cpp = he2->h_addr_list; + while (*cpp != NULL) { + *npp = memget((af == AF_INET) ? INADDRSZ : IN6ADDRSZ); + if (*npp == NULL) + goto cleanup1; + /* convert to mapped if required */ + if (af == AF_INET6 && he2->h_addrtype == AF_INET) { + memcpy(*npp, in6addr_mapped, + sizeof in6addr_mapped); + memcpy(*npp + sizeof in6addr_mapped, *cpp, + INADDRSZ); + } else { + memcpy(*npp, *cpp, + (af == AF_INET) ? INADDRSZ : IN6ADDRSZ); + } + cpp++; + npp++; + } + } + + he->h_aliases = memget(sizeof(char *) * (names)); + if (he->h_aliases == NULL) + goto cleanup1; + memset(he->h_aliases, 0, sizeof(char *) * (names)); + + /* copy aliases */ + npp = he->h_aliases; + cpp = (he1 != NULL) ? he1->h_aliases : he2->h_aliases; + while (*cpp != NULL) { + len = strlen (*cpp) + 1; + *npp = memget(len); + if (*npp == NULL) + goto cleanup2; + strcpy(*npp, *cpp); + npp++; + cpp++; + } + + /* copy hostname */ + he->h_name = memget(strlen((he1 != NULL) ? + he1->h_name : he2->h_name) + 1); + if (he->h_name == NULL) + goto cleanup2; + strcpy(he->h_name, (he1 != NULL) ? he1->h_name : he2->h_name); + + /* set address type and length */ + he->h_addrtype = af; + he->h_length = (af == AF_INET) ? INADDRSZ : IN6ADDRSZ; + return(he); + + cleanup2: + cpp = he->h_aliases; + while (*cpp != NULL) { + memput(*cpp, strlen(*cpp) + 1); + cpp++; + } + memput(he->h_aliases, sizeof(char *) * (names)); + + cleanup1: + cpp = he->h_addr_list; + while (*cpp != NULL) { + memput(*cpp, (af == AF_INET) ? INADDRSZ : IN6ADDRSZ); + *cpp = NULL; + cpp++; + } + memput(he->h_addr_list, sizeof(char *) * (addresses)); + + cleanup0: + memput(he, sizeof *he); + + no_recovery: + *error_num = NO_RECOVERY; + return (NULL); +} + +static struct net_data * +init() { + struct net_data *net_data; + + if (!(net_data = net_data_init(NULL))) + goto error; + if (!net_data->ho) { + net_data->ho = (*net_data->irs->ho_map)(net_data->irs); + if (!net_data->ho || !net_data->res) { + error: + errno = EIO; + if (net_data && net_data->res) + RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); + return (NULL); + } + + (*net_data->ho->res_set)(net_data->ho, net_data->res, NULL); + } + + return (net_data); +} + +static void +freepvt(struct net_data *net_data) { + if (net_data->ho_data) { + free(net_data->ho_data); + net_data->ho_data = NULL; + } +} + +static struct hostent * +fakeaddr(const char *name, int af, struct net_data *net_data) { + struct pvt *pvt; + + freepvt(net_data); + net_data->ho_data = malloc(sizeof (struct pvt)); + if (!net_data->ho_data) { + errno = ENOMEM; + RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); + return (NULL); + } + pvt = net_data->ho_data; +#ifndef __bsdi__ + /* + * Unlike its forebear(inet_aton), our friendly inet_pton() is strict + * in its interpretation of its input, and it will only return "1" if + * the input string is a formally valid(and thus unambiguous with + * respect to host names) internet address specification for this AF. + * + * This means "telnet 0xdeadbeef" and "telnet 127.1" are dead now. + */ + if (inet_pton(af, name, pvt->addr) != 1) { +#else + /* BSDI XXX + * We put this back to inet_aton -- we really want the old behavior + * Long live 127.1... + */ + if ((af != AF_INET || + inet_aton(name, (struct in_addr *)pvt->addr) != 1) && + inet_pton(af, name, pvt->addr) != 1) { +#endif + RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND); + return (NULL); + } + strncpy(pvt->name, name, NS_MAXDNAME); + pvt->name[NS_MAXDNAME] = '\0'; + if (af == AF_INET && (net_data->res->options & RES_USE_INET6) != 0U) { + map_v4v6_address(pvt->addr, pvt->addr); + af = AF_INET6; + } + pvt->host.h_addrtype = af; + switch(af) { + case AF_INET: + pvt->host.h_length = NS_INADDRSZ; + break; + case AF_INET6: + pvt->host.h_length = NS_IN6ADDRSZ; + break; + default: + errno = EAFNOSUPPORT; + RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); + return (NULL); + } + pvt->host.h_name = pvt->name; + pvt->host.h_aliases = pvt->aliases; + pvt->aliases[0] = NULL; + pvt->addrs[0] = (char *)pvt->addr; + pvt->addrs[1] = NULL; + pvt->host.h_addr_list = pvt->addrs; + RES_SET_H_ERRNO(net_data->res, NETDB_SUCCESS); + return (&pvt->host); +} + +#ifdef grot /*%< for future use in gethostbyaddr(), for "SUNSECURITY" */ + struct hostent *rhp; + char **haddr; + u_long old_options; + char hname2[MAXDNAME+1]; + + if (af == AF_INET) { + /* + * turn off search as the name should be absolute, + * 'localhost' should be matched by defnames + */ + strncpy(hname2, hp->h_name, MAXDNAME); + hname2[MAXDNAME] = '\0'; + old_options = net_data->res->options; + net_data->res->options &= ~RES_DNSRCH; + net_data->res->options |= RES_DEFNAMES; + if (!(rhp = gethostbyname(hname2))) { + net_data->res->options = old_options; + RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND); + return (NULL); + } + net_data->res->options = old_options; + for (haddr = rhp->h_addr_list; *haddr; haddr++) + if (!memcmp(*haddr, addr, INADDRSZ)) + break; + if (!*haddr) { + RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND); + return (NULL); + } + } +#endif /* grot */ +#endif /*__BIND_NOSTATIC*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/gethostent_r.c b/contrib/bind-9.5.2/lib/bind/irs/gethostent_r.c new file mode 100644 index 0000000000..fdb7ee225c --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/gethostent_r.c @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1998-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: gethostent_r.c,v 1.9 2005/09/03 12:41:37 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#if !defined(_REENTRANT) || !defined(DO_PTHREADS) + static int gethostent_r_not_required = 0; +#else +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HOST_R_RETURN + +static HOST_R_RETURN +copy_hostent(struct hostent *, struct hostent *, HOST_R_COPY_ARGS); + +HOST_R_RETURN +gethostbyname_r(const char *name, struct hostent *hptr, HOST_R_ARGS) { + struct hostent *he = gethostbyname(name); +#ifdef HOST_R_SETANSWER + int n = 0; +#endif + +#ifdef HOST_R_ERRNO + HOST_R_ERRNO; +#endif + +#ifdef HOST_R_SETANSWER + if (he == NULL || (n = copy_hostent(he, hptr, HOST_R_COPY)) != 0) + *answerp = NULL; + else + *answerp = hptr; + + return (n); +#else + if (he == NULL) + return (HOST_R_BAD); + + return (copy_hostent(he, hptr, HOST_R_COPY)); +#endif +} + +HOST_R_RETURN +gethostbyaddr_r(const char *addr, int len, int type, + struct hostent *hptr, HOST_R_ARGS) { + struct hostent *he = gethostbyaddr(addr, len, type); +#ifdef HOST_R_SETANSWER + int n = 0; +#endif + +#ifdef HOST_R_ERRNO + HOST_R_ERRNO; +#endif + +#ifdef HOST_R_SETANSWER + if (he == NULL || (n = copy_hostent(he, hptr, HOST_R_COPY)) != 0) + *answerp = NULL; + else + *answerp = hptr; + + return (n); +#else + if (he == NULL) + return (HOST_R_BAD); + + return (copy_hostent(he, hptr, HOST_R_COPY)); +#endif +} + +/*% + * These assume a single context is in operation per thread. + * If this is not the case we will need to call irs directly + * rather than through the base functions. + */ + +HOST_R_RETURN +gethostent_r(struct hostent *hptr, HOST_R_ARGS) { + struct hostent *he = gethostent(); +#ifdef HOST_R_SETANSWER + int n = 0; +#endif + +#ifdef HOST_R_ERRNO + HOST_R_ERRNO; +#endif + +#ifdef HOST_R_SETANSWER + if (he == NULL || (n = copy_hostent(he, hptr, HOST_R_COPY)) != 0) + *answerp = NULL; + else + *answerp = hptr; + + return (n); +#else + if (he == NULL) + return (HOST_R_BAD); + + return (copy_hostent(he, hptr, HOST_R_COPY)); +#endif +} + +HOST_R_SET_RETURN +#ifdef HOST_R_ENT_ARGS +sethostent_r(int stay_open, HOST_R_ENT_ARGS) +#else +sethostent_r(int stay_open) +#endif +{ +#ifdef HOST_R_ENT_ARGS + UNUSED(hdptr); +#endif + sethostent(stay_open); +#ifdef HOST_R_SET_RESULT + return (HOST_R_SET_RESULT); +#endif +} + +HOST_R_END_RETURN +#ifdef HOST_R_ENT_ARGS +endhostent_r(HOST_R_ENT_ARGS) +#else +endhostent_r(void) +#endif +{ +#ifdef HOST_R_ENT_ARGS + UNUSED(hdptr); +#endif + endhostent(); + HOST_R_END_RESULT(HOST_R_OK); +} + +/* Private */ + +#ifndef HOSTENT_DATA +static HOST_R_RETURN +copy_hostent(struct hostent *he, struct hostent *hptr, HOST_R_COPY_ARGS) { + char *cp; + char **ptr; + int i, n; + int nptr, len; + + /* Find out the amount of space required to store the answer. */ + nptr = 2; /*%< NULL ptrs */ + len = (char *)ALIGN(buf) - buf; + for (i = 0; he->h_addr_list[i]; i++, nptr++) { + len += he->h_length; + } + for (i = 0; he->h_aliases[i]; i++, nptr++) { + len += strlen(he->h_aliases[i]) + 1; + } + len += strlen(he->h_name) + 1; + len += nptr * sizeof(char*); + + if (len > buflen) { + errno = ERANGE; + return (HOST_R_BAD); + } + + /* copy address size and type */ + hptr->h_addrtype = he->h_addrtype; + n = hptr->h_length = he->h_length; + + ptr = (char **)ALIGN(buf); + cp = (char *)ALIGN(buf) + nptr * sizeof(char *); + + /* copy address list */ + hptr->h_addr_list = ptr; + for (i = 0; he->h_addr_list[i]; i++ , ptr++) { + memcpy(cp, he->h_addr_list[i], n); + hptr->h_addr_list[i] = cp; + cp += n; + } + hptr->h_addr_list[i] = NULL; + ptr++; + + /* copy official name */ + n = strlen(he->h_name) + 1; + strcpy(cp, he->h_name); + hptr->h_name = cp; + cp += n; + + /* copy aliases */ + hptr->h_aliases = ptr; + for (i = 0 ; he->h_aliases[i]; i++) { + n = strlen(he->h_aliases[i]) + 1; + strcpy(cp, he->h_aliases[i]); + hptr->h_aliases[i] = cp; + cp += n; + } + hptr->h_aliases[i] = NULL; + + return (HOST_R_OK); +} +#else /* !HOSTENT_DATA */ +static int +copy_hostent(struct hostent *he, struct hostent *hptr, HOST_R_COPY_ARGS) { + char *cp, *eob; + int i, n; + + /* copy address size and type */ + hptr->h_addrtype = he->h_addrtype; + n = hptr->h_length = he->h_length; + + /* copy up to first 35 addresses */ + i = 0; + cp = hdptr->hostbuf; + eob = hdptr->hostbuf + sizeof(hdptr->hostbuf); + hptr->h_addr_list = hdptr->h_addr_ptrs; + while (he->h_addr_list[i] && i < (_MAXADDRS)) { + if (n < (eob - cp)) { + memcpy(cp, he->h_addr_list[i], n); + hptr->h_addr_list[i] = cp; + cp += n; + } else { + break; + } + i++; + } + hptr->h_addr_list[i] = NULL; + + /* copy official name */ + if ((n = strlen(he->h_name) + 1) < (eob - cp)) { + strcpy(cp, he->h_name); + hptr->h_name = cp; + cp += n; + } else { + return (-1); + } + + /* copy aliases */ + i = 0; + hptr->h_aliases = hdptr->host_aliases; + while (he->h_aliases[i] && i < (_MAXALIASES-1)) { + if ((n = strlen(he->h_aliases[i]) + 1) < (eob - cp)) { + strcpy(cp, he->h_aliases[i]); + hptr->h_aliases[i] = cp; + cp += n; + } else { + break; + } + i++; + } + hptr->h_aliases[i] = NULL; + + return (HOST_R_OK); +} +#endif /* !HOSTENT_DATA */ +#else /* HOST_R_RETURN */ + static int gethostent_r_unknown_system = 0; +#endif /* HOST_R_RETURN */ +#endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/getnameinfo.c b/contrib/bind-9.5.2/lib/bind/irs/getnameinfo.c new file mode 100644 index 0000000000..89c8230ef9 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/getnameinfo.c @@ -0,0 +1,334 @@ +/* + * Issues to be discussed: + * - Thread safe-ness must be checked + */ + +#if ( defined(__linux__) || defined(__linux) || defined(LINUX) ) +#ifndef IF_NAMESIZE +# ifdef IFNAMSIZ +# define IF_NAMESIZE IFNAMSIZ +# else +# define IF_NAMESIZE 16 +# endif +#endif +#endif + +/* + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by WIDE Project and + * its contributors. + * 4. 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. + */ + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/*% + * Note that a_off will be dynamically adjusted so that to be consistent + * with the definition of sockaddr_in{,6}. + * The value presented below is just a guess. + */ +static struct afd { + int a_af; + int a_addrlen; + size_t a_socklen; + int a_off; +} afdl [] = { + /* first entry is linked last... */ + {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), + offsetof(struct sockaddr_in, sin_addr)}, + {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), + offsetof(struct sockaddr_in6, sin6_addr)}, + {0, 0, 0, 0}, +}; + +struct sockinet { +#ifdef HAVE_SA_LEN + u_char si_len; +#endif + u_char si_family; + u_short si_port; +}; + +static int ip6_parsenumeric __P((const struct sockaddr *, const char *, char *, + size_t, int)); +#ifdef HAVE_SIN6_SCOPE_ID +static int ip6_sa2str __P((const struct sockaddr_in6 *, char *, size_t, int)); +#endif + +int +getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) + const struct sockaddr *sa; + size_t salen; + char *host; + size_t hostlen; + char *serv; + size_t servlen; + int flags; +{ + struct afd *afd; + struct servent *sp; + struct hostent *hp; + u_short port; +#ifdef HAVE_SA_LEN + size_t len; +#endif + int family, i; + const char *addr; + char *p; + char numserv[512]; + char numaddr[512]; + const struct sockaddr_in6 *sin6; + + if (sa == NULL) + return EAI_FAIL; + +#ifdef HAVE_SA_LEN + len = sa->sa_len; + if (len != salen) return 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; + } + return EAI_FAMILY; + + found: + if (salen != afd->a_socklen) return EAI_FAIL; + + port = ((const struct sockinet *)sa)->si_port; /*%< network byte order */ + addr = (const char *)sa + afd->a_off; + + if (serv == NULL || servlen == 0U) { + /* + * rfc2553bis says that serv == NULL or servlen == 0 means that + * the caller does not want the result. + */ + } else if (flags & NI_NUMERICSERV) { + sprintf(numserv, "%d", ntohs(port)); + if (strlen(numserv) > servlen) + return EAI_MEMORY; + strcpy(serv, numserv); + } else { + sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp"); + if (sp) { + if (strlen(sp->s_name) + 1 > servlen) + return EAI_MEMORY; + strcpy(serv, sp->s_name); + } else + return EAI_NONAME; + } + + switch (sa->sa_family) { + case AF_INET: + if (ntohl(*(const u_int32_t *)addr) >> IN_CLASSA_NSHIFT == 0) + flags |= NI_NUMERICHOST; + break; + case AF_INET6: + sin6 = (const struct sockaddr_in6 *)sa; + switch (sin6->sin6_addr.s6_addr[0]) { + case 0x00: + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) + ; + else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) + ; + else + flags |= NI_NUMERICHOST; + break; + default: + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) + flags |= NI_NUMERICHOST; + else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) + flags |= NI_NUMERICHOST; + break; + } + break; + } + if (host == NULL || hostlen == 0U) { + /* + * rfc2553bis says that host == NULL or hostlen == 0 means that + * the caller does not want the result. + */ + } else if (flags & NI_NUMERICHOST) { + goto numeric; + } else { + hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af); + + if (hp) { + if (flags & NI_NOFQDN) { + p = strchr(hp->h_name, '.'); + if (p) *p = '\0'; + } + if (strlen(hp->h_name) + 1 > hostlen) + return EAI_MEMORY; + strcpy(host, hp->h_name); + } else { + if (flags & NI_NAMEREQD) + return EAI_NONAME; + numeric: + switch(afd->a_af) { + case AF_INET6: + { + int error; + + if ((error = ip6_parsenumeric(sa, addr, host, + hostlen, + flags)) != 0) + return(error); + break; + } + + default: + if (inet_ntop(afd->a_af, addr, numaddr, + sizeof(numaddr)) == NULL) + return EAI_NONAME; + if (strlen(numaddr) + 1 > hostlen) + return EAI_MEMORY; + strcpy(host, numaddr); + } + } + } + return(0); +} + +static int +ip6_parsenumeric(const struct sockaddr *sa, const char *addr, char *host, + size_t hostlen, int flags) +{ + size_t numaddrlen; + char numaddr[512]; + +#ifndef HAVE_SIN6_SCOPE_ID + UNUSED(sa); + UNUSED(flags); +#endif + + if (inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr)) + == NULL) + return EAI_SYSTEM; + + numaddrlen = strlen(numaddr); + if (numaddrlen + 1 > hostlen) /*%< don't forget terminator */ + return EAI_MEMORY; + strcpy(host, numaddr); + +#ifdef HAVE_SIN6_SCOPE_ID + if (((const struct sockaddr_in6 *)sa)->sin6_scope_id) { + char scopebuf[MAXHOSTNAMELEN]; /*%< XXX */ + int scopelen; + + /* ip6_sa2str never fails */ + scopelen = ip6_sa2str((const struct sockaddr_in6 *)sa, + scopebuf, sizeof(scopebuf), flags); + + if (scopelen + 1 + numaddrlen + 1 > hostlen) + return EAI_MEMORY; + + /* construct */ + memcpy(host + numaddrlen + 1, scopebuf, + scopelen); + host[numaddrlen] = SCOPE_DELIMITER; + host[numaddrlen + 1 + scopelen] = '\0'; + } +#endif + + return 0; +} + +#ifdef HAVE_SIN6_SCOPE_ID +/* ARGSUSED */ +static int +ip6_sa2str(const struct sockaddr_in6 *sa6, char *buf, + size_t bufsiz, int flags) +{ +#ifdef USE_IFNAMELINKID + unsigned int ifindex = (unsigned int)sa6->sin6_scope_id; + const struct in6_addr *a6 = &sa6->sin6_addr; +#endif + char tmp[64]; + +#ifdef NI_NUMERICSCOPE + if (flags & NI_NUMERICSCOPE) { + sprintf(tmp, "%u", sa6->sin6_scope_id); + if (bufsiz != 0U) { + strncpy(buf, tmp, bufsiz - 1); + buf[bufsiz - 1] = '\0'; + } + return(strlen(tmp)); + } +#endif + +#ifdef USE_IFNAMELINKID + /* + * For a link-local address, convert the index to an interface + * name, assuming a one-to-one mapping between links and interfaces. + * Note, however, that this assumption is stronger than the + * specification of the scoped address architecture; the + * specficication says that more than one interfaces can belong to + * a single link. + */ + + /* if_indextoname() does not take buffer size. not a good api... */ + if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) && + bufsiz >= IF_NAMESIZE) { + char *p = if_indextoname(ifindex, buf); + if (p) { + return(strlen(p)); + } + } +#endif + + /* last resort */ + sprintf(tmp, "%u", sa6->sin6_scope_id); + if (bufsiz != 0U) { + strncpy(buf, tmp, bufsiz - 1); + buf[bufsiz - 1] = '\0'; + } + return(strlen(tmp)); +} +#endif + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/getnetent.c b/contrib/bind-9.5.2/lib/bind/irs/getnetent.c new file mode 100644 index 0000000000..a6abe7175b --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/getnetent.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: getnetent.c,v 1.7 2005/04/27 04:56:25 sra Exp $"; +#endif + +/* Imports */ + +#include "port_before.h" + +#if !defined(__BIND_NOSTATIC) + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "irs_data.h" + +/* Definitions */ + +struct pvt { + struct netent netent; + char * aliases[1]; + char name[MAXDNAME + 1]; +}; + +/* Forward */ + +static struct net_data *init(void); +static struct netent *nw_to_net(struct nwent *, struct net_data *); +static void freepvt(struct net_data *); +static struct netent *fakeaddr(const char *, int af, struct net_data *); + +/* Portability */ + +#ifndef INADDR_NONE +# define INADDR_NONE 0xffffffff +#endif + +/* Public */ + +struct netent * +getnetent() { + struct net_data *net_data = init(); + + return (getnetent_p(net_data)); +} + +struct netent * +getnetbyname(const char *name) { + struct net_data *net_data = init(); + + return (getnetbyname_p(name, net_data)); +} + +struct netent * +getnetbyaddr(unsigned long net, int type) { + struct net_data *net_data = init(); + + return (getnetbyaddr_p(net, type, net_data)); +} + +void +setnetent(int stayopen) { + struct net_data *net_data = init(); + + setnetent_p(stayopen, net_data); +} + + +void +endnetent() { + struct net_data *net_data = init(); + + endnetent_p(net_data); +} + +/* Shared private. */ + +struct netent * +getnetent_p(struct net_data *net_data) { + struct irs_nw *nw; + + if (!net_data || !(nw = net_data->nw)) + return (NULL); + net_data->nww_last = (*nw->next)(nw); + net_data->nw_last = nw_to_net(net_data->nww_last, net_data); + return (net_data->nw_last); +} + +struct netent * +getnetbyname_p(const char *name, struct net_data *net_data) { + struct irs_nw *nw; + struct netent *np; + char **nap; + + if (!net_data || !(nw = net_data->nw)) + return (NULL); + if (net_data->nw_stayopen && net_data->nw_last) { + if (!strcmp(net_data->nw_last->n_name, name)) + return (net_data->nw_last); + for (nap = net_data->nw_last->n_aliases; nap && *nap; nap++) + if (!strcmp(name, *nap)) + return (net_data->nw_last); + } + if ((np = fakeaddr(name, AF_INET, net_data)) != NULL) + return (np); + net_data->nww_last = (*nw->byname)(nw, name, AF_INET); + net_data->nw_last = nw_to_net(net_data->nww_last, net_data); + if (!net_data->nw_stayopen) + endnetent(); + return (net_data->nw_last); +} + +struct netent * +getnetbyaddr_p(unsigned long net, int type, struct net_data *net_data) { + struct irs_nw *nw; + u_char addr[4]; + int bits; + + if (!net_data || !(nw = net_data->nw)) + return (NULL); + if (net_data->nw_stayopen && net_data->nw_last) + if (type == net_data->nw_last->n_addrtype && + net == net_data->nw_last->n_net) + return (net_data->nw_last); + + /* cannonize net(host order) */ + if (net < 256UL) { + net <<= 24; + bits = 8; + } else if (net < 65536UL) { + net <<= 16; + bits = 16; + } else if (net < 16777216UL) { + net <<= 8; + bits = 24; + } else + bits = 32; + + /* convert to net order */ + addr[0] = (0xFF000000 & net) >> 24; + addr[1] = (0x00FF0000 & net) >> 16; + addr[2] = (0x0000FF00 & net) >> 8; + addr[3] = (0x000000FF & net); + + /* reduce bits to as close to natural number as possible */ + if ((bits == 32) && (addr[0] < 224) && (addr[3] == 0)) { + if ((addr[0] < 192) && (addr[2] == 0)) { + if ((addr[0] < 128) && (addr[1] == 0)) + bits = 8; + else + bits = 16; + } else { + bits = 24; + } + } + + net_data->nww_last = (*nw->byaddr)(nw, addr, bits, AF_INET); + net_data->nw_last = nw_to_net(net_data->nww_last, net_data); + if (!net_data->nw_stayopen) + endnetent(); + return (net_data->nw_last); +} + + + + +void +setnetent_p(int stayopen, struct net_data *net_data) { + struct irs_nw *nw; + + if (!net_data || !(nw = net_data->nw)) + return; + freepvt(net_data); + (*nw->rewind)(nw); + net_data->nw_stayopen = (stayopen != 0); + if (stayopen == 0) + net_data_minimize(net_data); +} + +void +endnetent_p(struct net_data *net_data) { + struct irs_nw *nw; + + if ((net_data != NULL) && ((nw = net_data->nw) != NULL)) + (*nw->minimize)(nw); +} + +/* Private */ + +static struct net_data * +init() { + struct net_data *net_data; + + if (!(net_data = net_data_init(NULL))) + goto error; + if (!net_data->nw) { + net_data->nw = (*net_data->irs->nw_map)(net_data->irs); + + if (!net_data->nw || !net_data->res) { + error: + errno = EIO; + return (NULL); + } + (*net_data->nw->res_set)(net_data->nw, net_data->res, NULL); + } + + return (net_data); +} + +static void +freepvt(struct net_data *net_data) { + if (net_data->nw_data) { + free(net_data->nw_data); + net_data->nw_data = NULL; + } +} + +static struct netent * +fakeaddr(const char *name, int af, struct net_data *net_data) { + struct pvt *pvt; + const char *cp; + u_long tmp; + + if (af != AF_INET) { + /* XXX should support IPv6 some day */ + errno = EAFNOSUPPORT; + RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); + return (NULL); + } + if (!isascii((unsigned char)(name[0])) || + !isdigit((unsigned char)(name[0]))) + return (NULL); + for (cp = name; *cp; ++cp) + if (!isascii(*cp) || (!isdigit((unsigned char)*cp) && *cp != '.')) + return (NULL); + if (*--cp == '.') + return (NULL); + + /* All-numeric, no dot at the end. */ + + tmp = inet_network(name); + if (tmp == INADDR_NONE) { + RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND); + return (NULL); + } + + /* Valid network number specified. + * Fake up a netent as if we'd actually + * done a lookup. + */ + freepvt(net_data); + net_data->nw_data = malloc(sizeof (struct pvt)); + if (!net_data->nw_data) { + errno = ENOMEM; + RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); + return (NULL); + } + pvt = net_data->nw_data; + + strncpy(pvt->name, name, MAXDNAME); + pvt->name[MAXDNAME] = '\0'; + pvt->netent.n_name = pvt->name; + pvt->netent.n_addrtype = AF_INET; + pvt->netent.n_aliases = pvt->aliases; + pvt->aliases[0] = NULL; + pvt->netent.n_net = tmp; + + return (&pvt->netent); +} + +static struct netent * +nw_to_net(struct nwent *nwent, struct net_data *net_data) { + struct pvt *pvt; + u_long addr = 0; + int i; + int msbyte; + + if (!nwent || nwent->n_addrtype != AF_INET) + return (NULL); + freepvt(net_data); + net_data->nw_data = malloc(sizeof (struct pvt)); + if (!net_data->nw_data) { + errno = ENOMEM; + RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); + return (NULL); + } + pvt = net_data->nw_data; + pvt->netent.n_name = nwent->n_name; + pvt->netent.n_aliases = nwent->n_aliases; + pvt->netent.n_addrtype = nwent->n_addrtype; + +/*% + * What this code does: Converts net addresses from network to host form. + * + * msbyte: the index of the most significant byte in the n_addr array. + * + * Shift bytes in significant order into addr. When all signicant + * bytes are in, zero out bits in the LSB that are not part of the network. + */ + msbyte = nwent->n_length / 8 + + ((nwent->n_length % 8) != 0 ? 1 : 0) - 1; + for (i = 0; i <= msbyte; i++) + addr = (addr << 8) | ((unsigned char *)nwent->n_addr)[i]; + i = (32 - nwent->n_length) % 8; + if (i != 0) + addr &= ~((1 << (i + 1)) - 1); + pvt->netent.n_net = addr; + return (&pvt->netent); +} + +#endif /*__BIND_NOSTATIC*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/getnetent_r.c b/contrib/bind-9.5.2/lib/bind/irs/getnetent_r.c new file mode 100644 index 0000000000..9fb52bc394 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/getnetent_r.c @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1998-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: getnetent_r.c,v 1.6 2005/09/03 12:41:38 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#if !defined(_REENTRANT) || !defined(DO_PTHREADS) + static int getnetent_r_not_required = 0; +#else +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef NET_R_RETURN + +static NET_R_RETURN +copy_netent(struct netent *, struct netent *, NET_R_COPY_ARGS); + +NET_R_RETURN +getnetbyname_r(const char *name, struct netent *nptr, NET_R_ARGS) { + struct netent *ne = getnetbyname(name); +#ifdef NET_R_SETANSWER + int n = 0; + + if (ne == NULL || (n = copy_netent(ne, nptr, NET_R_COPY)) != 0) + *answerp = NULL; + else + *answerp = ne; + if (ne == NULL) + *h_errnop = h_errno; + return (n); +#else + if (ne == NULL) + return (NET_R_BAD); + + return (copy_netent(ne, nptr, NET_R_COPY)); +#endif +} + +#ifndef GETNETBYADDR_ADDR_T +#define GETNETBYADDR_ADDR_T long +#endif +NET_R_RETURN +getnetbyaddr_r(GETNETBYADDR_ADDR_T addr, int type, struct netent *nptr, NET_R_ARGS) { + struct netent *ne = getnetbyaddr(addr, type); +#ifdef NET_R_SETANSWER + int n = 0; + + if (ne == NULL || (n = copy_netent(ne, nptr, NET_R_COPY)) != 0) + *answerp = NULL; + else + *answerp = ne; + if (ne == NULL) + *h_errnop = h_errno; + return (n); +#else + + if (ne == NULL) + return (NET_R_BAD); + + return (copy_netent(ne, nptr, NET_R_COPY)); +#endif +} + +/*% + * These assume a single context is in operation per thread. + * If this is not the case we will need to call irs directly + * rather than through the base functions. + */ + +NET_R_RETURN +getnetent_r(struct netent *nptr, NET_R_ARGS) { + struct netent *ne = getnetent(); +#ifdef NET_R_SETANSWER + int n = 0; + + if (ne == NULL || (n = copy_netent(ne, nptr, NET_R_COPY)) != 0) + *answerp = NULL; + else + *answerp = ne; + if (ne == NULL) + *h_errnop = h_errno; + return (n); +#else + + if (ne == NULL) + return (NET_R_BAD); + + return (copy_netent(ne, nptr, NET_R_COPY)); +#endif +} + +NET_R_SET_RETURN +#ifdef NET_R_ENT_ARGS +setnetent_r(int stay_open, NET_R_ENT_ARGS) +#else +setnetent_r(int stay_open) +#endif +{ +#ifdef NET_R_ENT_ARGS + UNUSED(ndptr); +#endif + setnetent(stay_open); +#ifdef NET_R_SET_RESULT + return (NET_R_SET_RESULT); +#endif +} + +NET_R_END_RETURN +#ifdef NET_R_ENT_ARGS +endnetent_r(NET_R_ENT_ARGS) +#else +endnetent_r() +#endif +{ +#ifdef NET_R_ENT_ARGS + UNUSED(ndptr); +#endif + endnetent(); + NET_R_END_RESULT(NET_R_OK); +} + +/* Private */ + +#ifndef NETENT_DATA +static NET_R_RETURN +copy_netent(struct netent *ne, struct netent *nptr, NET_R_COPY_ARGS) { + char *cp; + int i, n; + int numptr, len; + + /* Find out the amount of space required to store the answer. */ + numptr = 1; /*%< NULL ptr */ + len = (char *)ALIGN(buf) - buf; + for (i = 0; ne->n_aliases[i]; i++, numptr++) { + len += strlen(ne->n_aliases[i]) + 1; + } + len += strlen(ne->n_name) + 1; + len += numptr * sizeof(char*); + + if (len > (int)buflen) { + errno = ERANGE; + return (NET_R_BAD); + } + + /* copy net value and type */ + nptr->n_addrtype = ne->n_addrtype; + nptr->n_net = ne->n_net; + + cp = (char *)ALIGN(buf) + numptr * sizeof(char *); + + /* copy official name */ + n = strlen(ne->n_name) + 1; + strcpy(cp, ne->n_name); + nptr->n_name = cp; + cp += n; + + /* copy aliases */ + nptr->n_aliases = (char **)ALIGN(buf); + for (i = 0 ; ne->n_aliases[i]; i++) { + n = strlen(ne->n_aliases[i]) + 1; + strcpy(cp, ne->n_aliases[i]); + nptr->n_aliases[i] = cp; + cp += n; + } + nptr->n_aliases[i] = NULL; + + return (NET_R_OK); +} +#else /* !NETENT_DATA */ +static int +copy_netent(struct netent *ne, struct netent *nptr, NET_R_COPY_ARGS) { + char *cp, *eob; + int i, n; + + /* copy net value and type */ + nptr->n_addrtype = ne->n_addrtype; + nptr->n_net = ne->n_net; + + /* copy official name */ + cp = ndptr->line; + eob = ndptr->line + sizeof(ndptr->line); + if ((n = strlen(ne->n_name) + 1) < (eob - cp)) { + strcpy(cp, ne->n_name); + nptr->n_name = cp; + cp += n; + } else { + return (-1); + } + + /* copy aliases */ + i = 0; + nptr->n_aliases = ndptr->net_aliases; + while (ne->n_aliases[i] && i < (_MAXALIASES-1)) { + if ((n = strlen(ne->n_aliases[i]) + 1) < (eob - cp)) { + strcpy(cp, ne->n_aliases[i]); + nptr->n_aliases[i] = cp; + cp += n; + } else { + break; + } + i++; + } + nptr->n_aliases[i] = NULL; + + return (NET_R_OK); +} +#endif /* !NETENT_DATA */ +#else /* NET_R_RETURN */ + static int getnetent_r_unknown_system = 0; +#endif /* NET_R_RETURN */ +#endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/getnetgrent.c b/contrib/bind-9.5.2/lib/bind/irs/getnetgrent.c new file mode 100644 index 0000000000..697de4bd80 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/getnetgrent.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: getnetgrent.c,v 1.4.672.1 2008/02/27 00:05:45 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* Imports */ + +#include "port_before.h" + +#if !defined(__BIND_NOSTATIC) + +#include + +#include +#include + +#include +#include +#include + +#include + +#include "port_after.h" + +#include "irs_data.h" + +/* Forward */ + +static struct net_data *init(void); + + +/* Public */ + +#ifndef SETNETGRENT_ARGS +#define SETNETGRENT_ARGS const char *netgroup +#endif +void +setnetgrent(SETNETGRENT_ARGS) { + struct net_data *net_data = init(); + + setnetgrent_p(netgroup, net_data); +} + +void +endnetgrent(void) { + struct net_data *net_data = init(); + + endnetgrent_p(net_data); +} + +#ifndef INNETGR_ARGS +#define INNETGR_ARGS const char *netgroup, const char *host, \ + const char *user, const char *domain +#endif +int +innetgr(INNETGR_ARGS) { + struct net_data *net_data = init(); + + return (innetgr_p(netgroup, host, user, domain, net_data)); +} + +int +getnetgrent(NGR_R_CONST char **host, NGR_R_CONST char **user, + NGR_R_CONST char **domain) +{ + struct net_data *net_data = init(); + const char *ch, *cu, *cd; + int ret; + + ret = getnetgrent_p(&ch, &cu, &cd, net_data); + if (ret != 1) + return (ret); + + DE_CONST(ch, *host); + DE_CONST(cu, *user); + DE_CONST(cd, *domain); + return (ret); +} + +/* Shared private. */ + +void +setnetgrent_p(const char *netgroup, struct net_data *net_data) { + struct irs_ng *ng; + + if ((net_data != NULL) && ((ng = net_data->ng) != NULL)) + (*ng->rewind)(ng, netgroup); +} + +void +endnetgrent_p(struct net_data *net_data) { + struct irs_ng *ng; + + if (!net_data) + return; + if ((ng = net_data->ng) != NULL) + (*ng->close)(ng); + net_data->ng = NULL; +} + +int +innetgr_p(const char *netgroup, const char *host, + const char *user, const char *domain, + struct net_data *net_data) { + struct irs_ng *ng; + + if (!net_data || !(ng = net_data->ng)) + return (0); + return ((*ng->test)(ng, netgroup, host, user, domain)); +} + +int +getnetgrent_p(const char **host, const char **user, const char **domain, + struct net_data *net_data ) { + struct irs_ng *ng; + + if (!net_data || !(ng = net_data->ng)) + return (0); + return ((*ng->next)(ng, host, user, domain)); +} + +/* Private */ + +static struct net_data * +init(void) { + struct net_data *net_data; + + if (!(net_data = net_data_init(NULL))) + goto error; + if (!net_data->ng) { + net_data->ng = (*net_data->irs->ng_map)(net_data->irs); + if (!net_data->ng) { + error: + errno = EIO; + return (NULL); + } + } + + return (net_data); +} + +#endif /*__BIND_NOSTATIC*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/getnetgrent_r.c b/contrib/bind-9.5.2/lib/bind/irs/getnetgrent_r.c new file mode 100644 index 0000000000..331f7b360f --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/getnetgrent_r.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1998-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: getnetgrent_r.c,v 1.11.558.2 2008/02/28 05:46:12 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#if !defined(_REENTRANT) || !defined(DO_PTHREADS) + static int getnetgrent_r_not_required = 0; +#else +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef NGR_R_RETURN +#ifndef NGR_R_PRIVATE +#define NGR_R_PRIVATE 0 +#endif + +static NGR_R_RETURN +copy_protoent(NGR_R_CONST char **, NGR_R_CONST char **, NGR_R_CONST char **, + const char *, const char *, const char *, NGR_R_COPY_ARGS); + +NGR_R_RETURN +innetgr_r(const char *netgroup, const char *host, const char *user, + const char *domain) { + char *ng, *ho, *us, *dom; + + DE_CONST(netgroup, ng); + DE_CONST(host, ho); + DE_CONST(user, us); + DE_CONST(domain, dom); + + return (innetgr(ng, ho, us, dom)); +} + +/*% + * These assume a single context is in operation per thread. + * If this is not the case we will need to call irs directly + * rather than through the base functions. + */ + +NGR_R_RETURN +getnetgrent_r(NGR_R_CONST char **machinep, NGR_R_CONST char **userp, + NGR_R_CONST char **domainp, NGR_R_ARGS) +{ + NGR_R_CONST char *mp, *up, *dp; + int res = getnetgrent(&mp, &up, &dp); + + if (res != 1) + return (res); + + return (copy_protoent(machinep, userp, domainp, + mp, up, dp, NGR_R_COPY)); +} + +#if NGR_R_PRIVATE == 2 +struct private { + char *buf; +}; + +#endif +NGR_R_SET_RETURN +#ifdef NGR_R_SET_ARGS +setnetgrent_r(NGR_R_SET_CONST char *netgroup, NGR_R_SET_ARGS) +#else +setnetgrent_r(NGR_R_SET_CONST char *netgroup) +#endif +{ +#if NGR_R_PRIVATE == 2 + struct private *p; +#endif + char *tmp; +#if defined(NGR_R_SET_ARGS) && NGR_R_PRIVATE == 0 + UNUSED(buf); + UNUSED(buflen); +#endif + + DE_CONST(netgroup, tmp); + setnetgrent(tmp); + +#if NGR_R_PRIVATE == 1 + *buf = NULL; +#elif NGR_R_PRIVATE == 2 + *buf = p = malloc(sizeof(struct private)); + if (p == NULL) +#ifdef NGR_R_SET_RESULT + return (NGR_R_BAD); +#else + return; +#endif + p->buf = NULL; +#endif +#ifdef NGR_R_SET_RESULT + return (NGR_R_SET_RESULT); +#endif +} + +NGR_R_END_RETURN +#ifdef NGR_R_END_ARGS +endnetgrent_r(NGR_R_END_ARGS) +#else +endnetgrent_r(void) +#endif +{ +#if NGR_R_PRIVATE == 2 + struct private *p = buf; +#endif +#if defined(NGR_R_SET_ARGS) && NGR_R_PRIVATE == 0 + UNUSED(buf); + UNUSED(buflen); +#endif + + endnetgrent(); +#if NGR_R_PRIVATE == 1 + if (*buf != NULL) + free(*buf); + *buf = NULL; +#elif NGR_R_PRIVATE == 2 + if (p->buf != NULL) + free(p->buf); + free(p); +#endif + NGR_R_END_RESULT(NGR_R_OK); +} + +/* Private */ + +static int +copy_protoent(NGR_R_CONST char **machinep, NGR_R_CONST char **userp, + NGR_R_CONST char **domainp, const char *mp, const char *up, + const char *dp, NGR_R_COPY_ARGS) +{ +#if NGR_R_PRIVATE == 2 + struct private *p = buf; +#endif + char *cp; + int n; + int len; + + /* Find out the amount of space required to store the answer. */ + len = 0; + if (mp != NULL) len += strlen(mp) + 1; + if (up != NULL) len += strlen(up) + 1; + if (dp != NULL) len += strlen(dp) + 1; + +#if NGR_R_PRIVATE == 1 + if (*buf != NULL) + free(*buf); + *buf = malloc(len); + if (*buf == NULL) + return(NGR_R_BAD); + cp = *buf; +#elif NGR_R_PRIVATE == 2 + if (p->buf) + free(p->buf); + p->buf = malloc(len); + if (p->buf == NULL) + return(NGR_R_BAD); + cp = p->buf; +#else + if (len > (int)buflen) { + errno = ERANGE; + return (NGR_R_BAD); + } + cp = buf; +#endif + + if (mp != NULL) { + n = strlen(mp) + 1; + strcpy(cp, mp); + *machinep = cp; + cp += n; + } else + *machinep = NULL; + + if (up != NULL) { + n = strlen(up) + 1; + strcpy(cp, up); + *userp = cp; + cp += n; + } else + *userp = NULL; + + if (dp != NULL) { + n = strlen(dp) + 1; + strcpy(cp, dp); + *domainp = cp; + cp += n; + } else + *domainp = NULL; + + return (NGR_R_OK); +} +#else /* NGR_R_RETURN */ + static int getnetgrent_r_unknown_system = 0; +#endif /* NGR_R_RETURN */ +#endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/getprotoent.c b/contrib/bind-9.5.2/lib/bind/irs/getprotoent.c new file mode 100644 index 0000000000..1e109f9659 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/getprotoent.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: getprotoent.c,v 1.4 2005/04/27 04:56:26 sra Exp $"; +#endif + +/* Imports */ + +#include "port_before.h" + +#if !defined(__BIND_NOSTATIC) + +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include "port_after.h" + +#include "irs_data.h" + +/* Forward */ + +static struct net_data *init(void); + +/* Public */ + +struct protoent * +getprotoent() { + struct net_data *net_data = init(); + + return (getprotoent_p(net_data)); +} + +struct protoent * +getprotobyname(const char *name) { + struct net_data *net_data = init(); + + return (getprotobyname_p(name, net_data)); +} + +struct protoent * +getprotobynumber(int proto) { + struct net_data *net_data = init(); + + return (getprotobynumber_p(proto, net_data)); +} + +void +setprotoent(int stayopen) { + struct net_data *net_data = init(); + + setprotoent_p(stayopen, net_data); +} + +void +endprotoent() { + struct net_data *net_data = init(); + + endprotoent_p(net_data); +} + +/* Shared private. */ + +struct protoent * +getprotoent_p(struct net_data *net_data) { + struct irs_pr *pr; + + if (!net_data || !(pr = net_data->pr)) + return (NULL); + net_data->pr_last = (*pr->next)(pr); + return (net_data->pr_last); +} + +struct protoent * +getprotobyname_p(const char *name, struct net_data *net_data) { + struct irs_pr *pr; + char **pap; + + if (!net_data || !(pr = net_data->pr)) + return (NULL); + if (net_data->pr_stayopen && net_data->pr_last) { + if (!strcmp(net_data->pr_last->p_name, name)) + return (net_data->pr_last); + for (pap = net_data->pr_last->p_aliases; pap && *pap; pap++) + if (!strcmp(name, *pap)) + return (net_data->pr_last); + } + net_data->pr_last = (*pr->byname)(pr, name); + if (!net_data->pr_stayopen) + endprotoent(); + return (net_data->pr_last); +} + +struct protoent * +getprotobynumber_p(int proto, struct net_data *net_data) { + struct irs_pr *pr; + + if (!net_data || !(pr = net_data->pr)) + return (NULL); + if (net_data->pr_stayopen && net_data->pr_last) + if (net_data->pr_last->p_proto == proto) + return (net_data->pr_last); + net_data->pr_last = (*pr->bynumber)(pr, proto); + if (!net_data->pr_stayopen) + endprotoent(); + return (net_data->pr_last); +} + +void +setprotoent_p(int stayopen, struct net_data *net_data) { + struct irs_pr *pr; + + if (!net_data || !(pr = net_data->pr)) + return; + (*pr->rewind)(pr); + net_data->pr_stayopen = (stayopen != 0); + if (stayopen == 0) + net_data_minimize(net_data); +} + +void +endprotoent_p(struct net_data *net_data) { + struct irs_pr *pr; + + if ((net_data != NULL) && ((pr = net_data->pr) != NULL)) + (*pr->minimize)(pr); +} + +/* Private */ + +static struct net_data * +init() { + struct net_data *net_data; + + if (!(net_data = net_data_init(NULL))) + goto error; + if (!net_data->pr) { + net_data->pr = (*net_data->irs->pr_map)(net_data->irs); + + if (!net_data->pr || !net_data->res) { + error: + errno = EIO; + return (NULL); + } + (*net_data->pr->res_set)(net_data->pr, net_data->res, NULL); + } + + return (net_data); +} + +#endif /*__BIND_NOSTATIC*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/getprotoent_r.c b/contrib/bind-9.5.2/lib/bind/irs/getprotoent_r.c new file mode 100644 index 0000000000..d5d9ae53b6 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/getprotoent_r.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1998-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: getprotoent_r.c,v 1.6 2006/08/01 01:14:16 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#if !defined(_REENTRANT) || !defined(DO_PTHREADS) + static int getprotoent_r_not_required = 0; +#else +#include +#include +#include +#include +#include +#include +#include + +#ifdef PROTO_R_RETURN + +static PROTO_R_RETURN +copy_protoent(struct protoent *, struct protoent *, PROTO_R_COPY_ARGS); + +PROTO_R_RETURN +getprotobyname_r(const char *name, struct protoent *pptr, PROTO_R_ARGS) { + struct protoent *pe = getprotobyname(name); +#ifdef PROTO_R_SETANSWER + int n = 0; + + if (pe == NULL || (n = copy_protoent(pe, pptr, PROTO_R_COPY)) != 0) + *answerp = NULL; + else + *answerp = pptr; + + return (n); +#else + if (pe == NULL) + return (PROTO_R_BAD); + + return (copy_protoent(pe, pptr, PROTO_R_COPY)); +#endif +} + +PROTO_R_RETURN +getprotobynumber_r(int proto, struct protoent *pptr, PROTO_R_ARGS) { + struct protoent *pe = getprotobynumber(proto); +#ifdef PROTO_R_SETANSWER + int n = 0; + + if (pe == NULL || (n = copy_protoent(pe, pptr, PROTO_R_COPY)) != 0) + *answerp = NULL; + else + *answerp = pptr; + + return (n); +#else + if (pe == NULL) + return (PROTO_R_BAD); + + return (copy_protoent(pe, pptr, PROTO_R_COPY)); +#endif +} + +/*% + * These assume a single context is in operation per thread. + * If this is not the case we will need to call irs directly + * rather than through the base functions. + */ + +PROTO_R_RETURN +getprotoent_r(struct protoent *pptr, PROTO_R_ARGS) { + struct protoent *pe = getprotoent(); +#ifdef PROTO_R_SETANSWER + int n = 0; + + if (pe == NULL || (n = copy_protoent(pe, pptr, PROTO_R_COPY)) != 0) + *answerp = NULL; + else + *answerp = pptr; + + return (n); +#else + if (pe == NULL) + return (PROTO_R_BAD); + + return (copy_protoent(pe, pptr, PROTO_R_COPY)); +#endif +} + +PROTO_R_SET_RETURN +#ifdef PROTO_R_ENT_ARGS +setprotoent_r(int stay_open, PROTO_R_ENT_ARGS) +#else +setprotoent_r(int stay_open) +#endif +{ +#ifdef PROTO_R_ENT_UNUSED + PROTO_R_ENT_UNUSED; +#endif + setprotoent(stay_open); +#ifdef PROTO_R_SET_RESULT + return (PROTO_R_SET_RESULT); +#endif +} + +PROTO_R_END_RETURN +#ifdef PROTO_R_ENT_ARGS +endprotoent_r(PROTO_R_ENT_ARGS) +#else +endprotoent_r() +#endif +{ +#ifdef PROTO_R_ENT_UNUSED + PROTO_R_ENT_UNUSED; +#endif + endprotoent(); + PROTO_R_END_RESULT(PROTO_R_OK); +} + +/* Private */ + +#ifndef PROTOENT_DATA +static PROTO_R_RETURN +copy_protoent(struct protoent *pe, struct protoent *pptr, PROTO_R_COPY_ARGS) { + char *cp; + int i, n; + int numptr, len; + + /* Find out the amount of space required to store the answer. */ + numptr = 1; /*%< NULL ptr */ + len = (char *)ALIGN(buf) - buf; + for (i = 0; pe->p_aliases[i]; i++, numptr++) { + len += strlen(pe->p_aliases[i]) + 1; + } + len += strlen(pe->p_name) + 1; + len += numptr * sizeof(char*); + + if (len > (int)buflen) { + errno = ERANGE; + return (PROTO_R_BAD); + } + + /* copy protocol value*/ + pptr->p_proto = pe->p_proto; + + cp = (char *)ALIGN(buf) + numptr * sizeof(char *); + + /* copy official name */ + n = strlen(pe->p_name) + 1; + strcpy(cp, pe->p_name); + pptr->p_name = cp; + cp += n; + + /* copy aliases */ + pptr->p_aliases = (char **)ALIGN(buf); + for (i = 0 ; pe->p_aliases[i]; i++) { + n = strlen(pe->p_aliases[i]) + 1; + strcpy(cp, pe->p_aliases[i]); + pptr->p_aliases[i] = cp; + cp += n; + } + pptr->p_aliases[i] = NULL; + + return (PROTO_R_OK); +} +#else /* !PROTOENT_DATA */ +static int +copy_protoent(struct protoent *pe, struct protoent *pptr, PROTO_R_COPY_ARGS) { + char *cp, *eob; + int i, n; + + /* copy protocol value */ + pptr->p_proto = pe->p_proto; + + /* copy official name */ + cp = pdptr->line; + eob = pdptr->line + sizeof(pdptr->line); + if ((n = strlen(pe->p_name) + 1) < (eob - cp)) { + strcpy(cp, pe->p_name); + pptr->p_name = cp; + cp += n; + } else { + return (-1); + } + + /* copy aliases */ + i = 0; + pptr->p_aliases = pdptr->proto_aliases; + while (pe->p_aliases[i] && i < (_MAXALIASES-1)) { + if ((n = strlen(pe->p_aliases[i]) + 1) < (eob - cp)) { + strcpy(cp, pe->p_aliases[i]); + pptr->p_aliases[i] = cp; + cp += n; + } else { + break; + } + i++; + } + pptr->p_aliases[i] = NULL; + + return (PROTO_R_OK); +} +#endif /* PROTOENT_DATA */ +#else /* PROTO_R_RETURN */ + static int getprotoent_r_unknown_system = 0; +#endif /* PROTO_R_RETURN */ +#endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/getpwent.c b/contrib/bind-9.5.2/lib/bind/irs/getpwent.c new file mode 100644 index 0000000000..c70f99e64c --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/getpwent.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: getpwent.c,v 1.3 2005/04/27 04:56:26 sra Exp $"; +#endif + +/* Imports */ + +#include "port_before.h" + +#if !defined(WANT_IRS_PW) || defined(__BIND_NOSTATIC) +static int __bind_irs_pw_unneeded; +#else + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "port_after.h" + +#include "irs_data.h" + +/* Forward */ + +static struct net_data * init(void); + +/* Public */ + +struct passwd * +getpwent(void) { + struct net_data *net_data = init(); + + return (getpwent_p(net_data)); +} + +struct passwd * +getpwnam(const char *name) { + struct net_data *net_data = init(); + + return (getpwnam_p(name, net_data)); +} + +struct passwd * +getpwuid(uid_t uid) { + struct net_data *net_data = init(); + + return (getpwuid_p(uid, net_data)); +} + +int +setpassent(int stayopen) { + struct net_data *net_data = init(); + + return (setpassent_p(stayopen, net_data)); +} + +#ifdef SETPWENT_VOID +void +setpwent() { + struct net_data *net_data = init(); + + setpwent_p(net_data); +} +#else +int +setpwent() { + struct net_data *net_data = init(); + + return (setpwent_p(net_data)); +} +#endif + +void +endpwent() { + struct net_data *net_data = init(); + + endpwent_p(net_data); +} + +/* Shared private. */ + +struct passwd * +getpwent_p(struct net_data *net_data) { + struct irs_pw *pw; + + if (!net_data || !(pw = net_data->pw)) + return (NULL); + net_data->pw_last = (*pw->next)(pw); + return (net_data->pw_last); +} + +struct passwd * +getpwnam_p(const char *name, struct net_data *net_data) { + struct irs_pw *pw; + + if (!net_data || !(pw = net_data->pw)) + return (NULL); + if (net_data->pw_stayopen && net_data->pw_last && + !strcmp(net_data->pw_last->pw_name, name)) + return (net_data->pw_last); + net_data->pw_last = (*pw->byname)(pw, name); + if (!net_data->pw_stayopen) + endpwent(); + return (net_data->pw_last); +} + +struct passwd * +getpwuid_p(uid_t uid, struct net_data *net_data) { + struct irs_pw *pw; + + if (!net_data || !(pw = net_data->pw)) + return (NULL); + if (net_data->pw_stayopen && net_data->pw_last && + net_data->pw_last->pw_uid == uid) + return (net_data->pw_last); + net_data->pw_last = (*pw->byuid)(pw, uid); + if (!net_data->pw_stayopen) + endpwent(); + return (net_data->pw_last); +} + +int +setpassent_p(int stayopen, struct net_data *net_data) { + struct irs_pw *pw; + + if (!net_data || !(pw = net_data->pw)) + return (0); + (*pw->rewind)(pw); + net_data->pw_stayopen = (stayopen != 0); + if (stayopen == 0) + net_data_minimize(net_data); + return (1); +} + +#ifdef SETPWENT_VOID +void +setpwent_p(struct net_data *net_data) { + (void) setpassent_p(0, net_data); +} +#else +int +setpwent_p(struct net_data *net_data) { + return (setpassent_p(0, net_data)); +} +#endif + +void +endpwent_p(struct net_data *net_data) { + struct irs_pw *pw; + + if ((net_data != NULL) && ((pw = net_data->pw) != NULL)) + (*pw->minimize)(pw); +} + +/* Private */ + +static struct net_data * +init() { + struct net_data *net_data; + if (!(net_data = net_data_init(NULL))) + goto error; + if (!net_data->pw) { + net_data->pw = (*net_data->irs->pw_map)(net_data->irs); + + if (!net_data->pw || !net_data->res) { + error: + errno = EIO; + return (NULL); + } + (*net_data->pw->res_set)(net_data->pw, net_data->res, NULL); + } + + return (net_data); +} + +#endif /* WANT_IRS_PW */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/getpwent_r.c b/contrib/bind-9.5.2/lib/bind/irs/getpwent_r.c new file mode 100644 index 0000000000..f754084317 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/getpwent_r.c @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1998-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: getpwent_r.c,v 1.8 2005/04/27 04:56:26 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#if !defined(_REENTRANT) || !defined(DO_PTHREADS) || !defined(WANT_IRS_PW) + static int getpwent_r_not_required = 0; +#else +#include +#include +#include +#include +#if (defined(POSIX_GETPWNAM_R) || defined(POSIX_GETPWUID_R)) +#if defined(_POSIX_PTHREAD_SEMANTICS) + /* turn off solaris remapping in */ +#undef _POSIX_PTHREAD_SEMANTICS +#include +#define _POSIX_PTHREAD_SEMANTICS 1 +#else +#define _UNIX95 1 +#include +#endif +#else +#include +#endif +#include + +#ifdef PASS_R_RETURN + +static int +copy_passwd(struct passwd *, struct passwd *, char *buf, int buflen); + +/* POSIX 1003.1c */ +#ifdef POSIX_GETPWNAM_R +int +__posix_getpwnam_r(const char *login, struct passwd *pwptr, + char *buf, size_t buflen, struct passwd **result) { +#else +int +getpwnam_r(const char *login, struct passwd *pwptr, + char *buf, size_t buflen, struct passwd **result) { +#endif + struct passwd *pw = getpwnam(login); + int res; + + if (pw == NULL) { + *result = NULL; + return (0); + } + + res = copy_passwd(pw, pwptr, buf, buflen); + *result = res ? NULL : pwptr; + return (res); +} + +#ifdef POSIX_GETPWNAM_R +struct passwd * +getpwnam_r(const char *login, struct passwd *pwptr, char *buf, int buflen) { + struct passwd *pw = getpwnam(login); + int res; + + if (pw == NULL) + return (NULL); + + res = copy_passwd(pw, pwptr, buf, buflen); + return (res ? NULL : pwptr); +} +#endif + +/* POSIX 1003.1c */ +#ifdef POSIX_GETPWUID_R +int +__posix_getpwuid_r(uid_t uid, struct passwd *pwptr, + char *buf, int buflen, struct passwd **result) { +#else +int +getpwuid_r(uid_t uid, struct passwd *pwptr, + char *buf, size_t buflen, struct passwd **result) { +#endif + struct passwd *pw = getpwuid(uid); + int res; + + if (pw == NULL) { + *result = NULL; + return (0); + } + + res = copy_passwd(pw, pwptr, buf, buflen); + *result = res ? NULL : pwptr; + return (res); +} + +#ifdef POSIX_GETPWUID_R +struct passwd * +getpwuid_r(uid_t uid, struct passwd *pwptr, char *buf, int buflen) { + struct passwd *pw = getpwuid(uid); + int res; + + if (pw == NULL) + return (NULL); + + res = copy_passwd(pw, pwptr, buf, buflen); + return (res ? NULL : pwptr); +} +#endif + +/*% + * These assume a single context is in operation per thread. + * If this is not the case we will need to call irs directly + * rather than through the base functions. + */ + +PASS_R_RETURN +getpwent_r(struct passwd *pwptr, PASS_R_ARGS) { + struct passwd *pw = getpwent(); + int res = 0; + + if (pw == NULL) + return (PASS_R_BAD); + + res = copy_passwd(pw, pwptr, buf, buflen); + return (res ? PASS_R_BAD : PASS_R_OK); +} + +PASS_R_SET_RETURN +#ifdef PASS_R_ENT_ARGS +setpassent_r(int stayopen, PASS_R_ENT_ARGS) +#else +setpassent_r(int stayopen) +#endif +{ + + setpassent(stayopen); +#ifdef PASS_R_SET_RESULT + return (PASS_R_SET_RESULT); +#endif +} + +PASS_R_SET_RETURN +#ifdef PASS_R_ENT_ARGS +setpwent_r(PASS_R_ENT_ARGS) +#else +setpwent_r(void) +#endif +{ + + setpwent(); +#ifdef PASS_R_SET_RESULT + return (PASS_R_SET_RESULT); +#endif +} + +PASS_R_END_RETURN +#ifdef PASS_R_ENT_ARGS +endpwent_r(PASS_R_ENT_ARGS) +#else +endpwent_r(void) +#endif +{ + + endpwent(); + PASS_R_END_RESULT(PASS_R_OK); +} + + +#ifdef HAS_FGETPWENT +PASS_R_RETURN +fgetpwent_r(FILE *f, struct passwd *pwptr, PASS_R_COPY_ARGS) { + struct passwd *pw = fgetpwent(f); + int res = 0; + + if (pw == NULL) + return (PASS_R_BAD); + + res = copy_passwd(pw, pwptr, PASS_R_COPY); + return (res ? PASS_R_BAD : PASS_R_OK ); +} +#endif + +/* Private */ + +static int +copy_passwd(struct passwd *pw, struct passwd *pwptr, char *buf, int buflen) { + char *cp; + int n; + int len; + + /* Find out the amount of space required to store the answer. */ + len = strlen(pw->pw_name) + 1; + len += strlen(pw->pw_passwd) + 1; +#ifdef HAVE_PW_CLASS + len += strlen(pw->pw_class) + 1; +#endif + len += strlen(pw->pw_gecos) + 1; + len += strlen(pw->pw_dir) + 1; + len += strlen(pw->pw_shell) + 1; + + if (len > buflen) { + errno = ERANGE; + return (ERANGE); + } + + /* copy fixed atomic values*/ + pwptr->pw_uid = pw->pw_uid; + pwptr->pw_gid = pw->pw_gid; +#ifdef HAVE_PW_CHANGE + pwptr->pw_change = pw->pw_change; +#endif +#ifdef HAVE_PW_EXPIRE + pwptr->pw_expire = pw->pw_expire; +#endif + + cp = buf; + + /* copy official name */ + n = strlen(pw->pw_name) + 1; + strcpy(cp, pw->pw_name); + pwptr->pw_name = cp; + cp += n; + + /* copy password */ + n = strlen(pw->pw_passwd) + 1; + strcpy(cp, pw->pw_passwd); + pwptr->pw_passwd = cp; + cp += n; + +#ifdef HAVE_PW_CLASS + /* copy class */ + n = strlen(pw->pw_class) + 1; + strcpy(cp, pw->pw_class); + pwptr->pw_class = cp; + cp += n; +#endif + + /* copy gecos */ + n = strlen(pw->pw_gecos) + 1; + strcpy(cp, pw->pw_gecos); + pwptr->pw_gecos = cp; + cp += n; + + /* copy directory */ + n = strlen(pw->pw_dir) + 1; + strcpy(cp, pw->pw_dir); + pwptr->pw_dir = cp; + cp += n; + + /* copy login shell */ + n = strlen(pw->pw_shell) + 1; + strcpy(cp, pw->pw_shell); + pwptr->pw_shell = cp; + cp += n; + + return (0); +} +#else /* PASS_R_RETURN */ + static int getpwent_r_unknown_system = 0; +#endif /* PASS_R_RETURN */ +#endif /* !def(_REENTRANT) || !def(DO_PTHREADS) || !def(WANT_IRS_PW) */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/getservent.c b/contrib/bind-9.5.2/lib/bind/irs/getservent.c new file mode 100644 index 0000000000..8de0db3058 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/getservent.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: getservent.c,v 1.4 2005/04/27 04:56:26 sra Exp $"; +#endif + +/* Imports */ + +#include "port_before.h" + +#if !defined(__BIND_NOSTATIC) + +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include "port_after.h" + +#include "irs_data.h" + +/* Forward */ + +static struct net_data *init(void); + +/* Public */ + +struct servent * +getservent(void) { + struct net_data *net_data = init(); + + return (getservent_p(net_data)); +} + +struct servent * +getservbyname(const char *name, const char *proto) { + struct net_data *net_data = init(); + + return (getservbyname_p(name, proto, net_data)); +} + +struct servent * +getservbyport(int port, const char *proto) { + struct net_data *net_data = init(); + + return (getservbyport_p(port, proto, net_data)); +} + +void +setservent(int stayopen) { + struct net_data *net_data = init(); + + setservent_p(stayopen, net_data); +} + +void +endservent() { + struct net_data *net_data = init(); + + endservent_p(net_data); +} + +/* Shared private. */ + +struct servent * +getservent_p(struct net_data *net_data) { + struct irs_sv *sv; + + if (!net_data || !(sv = net_data->sv)) + return (NULL); + net_data->sv_last = (*sv->next)(sv); + return (net_data->sv_last); +} + +struct servent * +getservbyname_p(const char *name, const char *proto, + struct net_data *net_data) { + struct irs_sv *sv; + char **sap; + + if (!net_data || !(sv = net_data->sv)) + return (NULL); + if (net_data->sv_stayopen && net_data->sv_last) + if (!proto || !strcmp(net_data->sv_last->s_proto, proto)) { + if (!strcmp(net_data->sv_last->s_name, name)) + return (net_data->sv_last); + for (sap = net_data->sv_last->s_aliases; + sap && *sap; sap++) + if (!strcmp(name, *sap)) + return (net_data->sv_last); + } + net_data->sv_last = (*sv->byname)(sv, name, proto); + if (!net_data->sv_stayopen) + endservent(); + return (net_data->sv_last); +} + +struct servent * +getservbyport_p(int port, const char *proto, struct net_data *net_data) { + struct irs_sv *sv; + + if (!net_data || !(sv = net_data->sv)) + return (NULL); + if (net_data->sv_stayopen && net_data->sv_last) + if (port == net_data->sv_last->s_port && + ( !proto || + !strcmp(net_data->sv_last->s_proto, proto))) + return (net_data->sv_last); + net_data->sv_last = (*sv->byport)(sv, port, proto); + return (net_data->sv_last); +} + +void +setservent_p(int stayopen, struct net_data *net_data) { + struct irs_sv *sv; + + if (!net_data || !(sv = net_data->sv)) + return; + (*sv->rewind)(sv); + net_data->sv_stayopen = (stayopen != 0); + if (stayopen == 0) + net_data_minimize(net_data); +} + +void +endservent_p(struct net_data *net_data) { + struct irs_sv *sv; + + if ((net_data != NULL) && ((sv = net_data->sv) != NULL)) + (*sv->minimize)(sv); +} + +/* Private */ + +static struct net_data * +init() { + struct net_data *net_data; + + if (!(net_data = net_data_init(NULL))) + goto error; + if (!net_data->sv) { + net_data->sv = (*net_data->irs->sv_map)(net_data->irs); + + if (!net_data->sv || !net_data->res) { + error: + errno = EIO; + return (NULL); + } + (*net_data->sv->res_set)(net_data->sv, net_data->res, NULL); + } + + return (net_data); +} + +#endif /*__BIND_NOSTATIC*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/getservent_r.c b/contrib/bind-9.5.2/lib/bind/irs/getservent_r.c new file mode 100644 index 0000000000..42d1e46163 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/getservent_r.c @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1998-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: getservent_r.c,v 1.6 2006/08/01 01:14:16 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#if !defined(_REENTRANT) || !defined(DO_PTHREADS) + static int getservent_r_not_required = 0; +#else +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef SERV_R_RETURN + +static SERV_R_RETURN +copy_servent(struct servent *, struct servent *, SERV_R_COPY_ARGS); + +SERV_R_RETURN +getservbyname_r(const char *name, const char *proto, + struct servent *sptr, SERV_R_ARGS) { + struct servent *se = getservbyname(name, proto); +#ifdef SERV_R_SETANSWER + int n = 0; + + if (se == NULL || (n = copy_servent(se, sptr, SERV_R_COPY)) != 0) + *answerp = NULL; + else + *answerp = sptr; + + return (n); +#else + if (se == NULL) + return (SERV_R_BAD); + + return (copy_servent(se, sptr, SERV_R_COPY)); +#endif +} + +SERV_R_RETURN +getservbyport_r(int port, const char *proto, + struct servent *sptr, SERV_R_ARGS) { + struct servent *se = getservbyport(port, proto); +#ifdef SERV_R_SETANSWER + int n = 0; + + if (se == NULL || (n = copy_servent(se, sptr, SERV_R_COPY)) != 0) + *answerp = NULL; + else + *answerp = sptr; + + return (n); +#else + if (se == NULL) + return (SERV_R_BAD); + + return (copy_servent(se, sptr, SERV_R_COPY)); +#endif +} + +/*% + * These assume a single context is in operation per thread. + * If this is not the case we will need to call irs directly + * rather than through the base functions. + */ + +SERV_R_RETURN +getservent_r(struct servent *sptr, SERV_R_ARGS) { + struct servent *se = getservent(); +#ifdef SERV_R_SETANSWER + int n = 0; + + if (se == NULL || (n = copy_servent(se, sptr, SERV_R_COPY)) != 0) + *answerp = NULL; + else + *answerp = sptr; + + return (n); +#else + if (se == NULL) + return (SERV_R_BAD); + + return (copy_servent(se, sptr, SERV_R_COPY)); +#endif +} + +SERV_R_SET_RETURN +#ifdef SERV_R_ENT_ARGS +setservent_r(int stay_open, SERV_R_ENT_ARGS) +#else +setservent_r(int stay_open) +#endif +{ +#ifdef SERV_R_ENT_UNUSED + SERV_R_ENT_UNUSED; +#endif + setservent(stay_open); +#ifdef SERV_R_SET_RESULT + return (SERV_R_SET_RESULT); +#endif +} + +SERV_R_END_RETURN +#ifdef SERV_R_ENT_ARGS +endservent_r(SERV_R_ENT_ARGS) +#else +endservent_r() +#endif +{ +#ifdef SERV_R_ENT_UNUSED + SERV_R_ENT_UNUSED; +#endif + endservent(); + SERV_R_END_RESULT(SERV_R_OK); +} + +/* Private */ + +#ifndef SERVENT_DATA +static SERV_R_RETURN +copy_servent(struct servent *se, struct servent *sptr, SERV_R_COPY_ARGS) { + char *cp; + int i, n; + int numptr, len; + + /* Find out the amount of space required to store the answer. */ + numptr = 1; /*%< NULL ptr */ + len = (char *)ALIGN(buf) - buf; + for (i = 0; se->s_aliases[i]; i++, numptr++) { + len += strlen(se->s_aliases[i]) + 1; + } + len += strlen(se->s_name) + 1; + len += strlen(se->s_proto) + 1; + len += numptr * sizeof(char*); + + if (len > (int)buflen) { + errno = ERANGE; + return (SERV_R_BAD); + } + + /* copy port value */ + sptr->s_port = se->s_port; + + cp = (char *)ALIGN(buf) + numptr * sizeof(char *); + + /* copy official name */ + n = strlen(se->s_name) + 1; + strcpy(cp, se->s_name); + sptr->s_name = cp; + cp += n; + + /* copy aliases */ + sptr->s_aliases = (char **)ALIGN(buf); + for (i = 0 ; se->s_aliases[i]; i++) { + n = strlen(se->s_aliases[i]) + 1; + strcpy(cp, se->s_aliases[i]); + sptr->s_aliases[i] = cp; + cp += n; + } + sptr->s_aliases[i] = NULL; + + /* copy proto */ + n = strlen(se->s_proto) + 1; + strcpy(cp, se->s_proto); + sptr->s_proto = cp; + cp += n; + + return (SERV_R_OK); +} +#else /* !SERVENT_DATA */ +static int +copy_servent(struct servent *se, struct servent *sptr, SERV_R_COPY_ARGS) { + char *cp, *eob; + int i, n; + + /* copy port value */ + sptr->s_port = se->s_port; + + /* copy official name */ + cp = sdptr->line; + eob = sdptr->line + sizeof(sdptr->line); + if ((n = strlen(se->s_name) + 1) < (eob - cp)) { + strcpy(cp, se->s_name); + sptr->s_name = cp; + cp += n; + } else { + return (-1); + } + + /* copy aliases */ + i = 0; + sptr->s_aliases = sdptr->serv_aliases; + while (se->s_aliases[i] && i < (_MAXALIASES-1)) { + if ((n = strlen(se->s_aliases[i]) + 1) < (eob - cp)) { + strcpy(cp, se->s_aliases[i]); + sptr->s_aliases[i] = cp; + cp += n; + } else { + break; + } + i++; + } + sptr->s_aliases[i] = NULL; + + /* copy proto */ + if ((n = strlen(se->s_proto) + 1) < (eob - cp)) { + strcpy(cp, se->s_proto); + sptr->s_proto = cp; + cp += n; + } else { + return (-1); + } + + return (SERV_R_OK); +} +#endif /* !SERVENT_DATA */ +#else /*SERV_R_RETURN */ + static int getservent_r_unknown_system = 0; +#endif /*SERV_R_RETURN */ +#endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/hesiod.c b/contrib/bind-9.5.2/lib/bind/irs/hesiod.c new file mode 100644 index 0000000000..80d669dbe0 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/hesiod.c @@ -0,0 +1,505 @@ +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: hesiod.c,v 1.7 2005/07/28 06:51:48 marka Exp $"; +#endif + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + + +/*! \file + * \brief + * hesiod.c --- the core portion of the hesiod resolver. + * + * This file is derived from the hesiod library from Project Athena; + * It has been extensively rewritten by Theodore Ts'o to have a more + * thread-safe interface. + * \author + * This file is primarily maintained by <tytso@mit.edu> and <ghudson@mit.edu>. + */ + +/* Imports */ + +#include "port_before.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "port_after.h" + +#include "pathnames.h" +#include "hesiod.h" +#include "hesiod_p.h" + +/* Forward */ + +int hesiod_init(void **context); +void hesiod_end(void *context); +char * hesiod_to_bind(void *context, const char *name, + const char *type); +char ** hesiod_resolve(void *context, const char *name, + const char *type); +void hesiod_free_list(void *context, char **list); + +static int parse_config_file(struct hesiod_p *ctx, const char *filename); +static char ** get_txt_records(struct hesiod_p *ctx, int class, + const char *name); +static int init(struct hesiod_p *ctx); + +/* Public */ + +/*% + * This function is called to initialize a hesiod_p. + */ +int +hesiod_init(void **context) { + struct hesiod_p *ctx; + char *cp; + + ctx = malloc(sizeof(struct hesiod_p)); + if (ctx == 0) { + errno = ENOMEM; + return (-1); + } + + memset(ctx, 0, sizeof (*ctx)); + + if (parse_config_file(ctx, _PATH_HESIOD_CONF) < 0) { +#ifdef DEF_RHS + /* + * Use compiled in defaults. + */ + ctx->LHS = malloc(strlen(DEF_LHS) + 1); + ctx->RHS = malloc(strlen(DEF_RHS) + 1); + if (ctx->LHS == NULL || ctx->RHS == NULL) { + errno = ENOMEM; + goto cleanup; + } + strcpy(ctx->LHS, DEF_LHS); /* (checked) */ + strcpy(ctx->RHS, DEF_RHS); /* (checked) */ +#else + goto cleanup; +#endif + } + /* + * The default RHS can be overridden by an environment + * variable. + */ + if ((cp = getenv("HES_DOMAIN")) != NULL) { + size_t RHSlen = strlen(cp) + 2; + if (ctx->RHS) + free(ctx->RHS); + ctx->RHS = malloc(RHSlen); + if (!ctx->RHS) { + errno = ENOMEM; + goto cleanup; + } + if (cp[0] == '.') { + strcpy(ctx->RHS, cp); /* (checked) */ + } else { + strcpy(ctx->RHS, "."); /* (checked) */ + strcat(ctx->RHS, cp); /* (checked) */ + } + } + + /* + * If there is no default hesiod realm set, we return an + * error. + */ + if (!ctx->RHS) { + errno = ENOEXEC; + goto cleanup; + } + +#if 0 + if (res_ninit(ctx->res) < 0) + goto cleanup; +#endif + + *context = ctx; + return (0); + + cleanup: + hesiod_end(ctx); + return (-1); +} + +/*% + * This function deallocates the hesiod_p + */ +void +hesiod_end(void *context) { + struct hesiod_p *ctx = (struct hesiod_p *) context; + int save_errno = errno; + + if (ctx->res) + res_nclose(ctx->res); + if (ctx->RHS) + free(ctx->RHS); + if (ctx->LHS) + free(ctx->LHS); + if (ctx->res && ctx->free_res) + (*ctx->free_res)(ctx->res); + free(ctx); + errno = save_errno; +} + +/*% + * This function takes a hesiod (name, type) and returns a DNS + * name which is to be resolved. + */ +char * +hesiod_to_bind(void *context, const char *name, const char *type) { + struct hesiod_p *ctx = (struct hesiod_p *) context; + char *bindname; + char **rhs_list = NULL; + const char *RHS, *cp; + + /* Decide what our RHS is, and set cp to the end of the actual name. */ + if ((cp = strchr(name, '@')) != NULL) { + if (strchr(cp + 1, '.')) + RHS = cp + 1; + else if ((rhs_list = hesiod_resolve(context, cp + 1, + "rhs-extension")) != NULL) + RHS = *rhs_list; + else { + errno = ENOENT; + return (NULL); + } + } else { + RHS = ctx->RHS; + cp = name + strlen(name); + } + + /* + * Allocate the space we need, including up to three periods and + * the terminating NUL. + */ + if ((bindname = malloc((cp - name) + strlen(type) + strlen(RHS) + + (ctx->LHS ? strlen(ctx->LHS) : 0) + 4)) == NULL) { + errno = ENOMEM; + if (rhs_list) + hesiod_free_list(context, rhs_list); + return NULL; + } + + /* Now put together the DNS name. */ + memcpy(bindname, name, cp - name); + bindname[cp - name] = '\0'; + strcat(bindname, "."); + strcat(bindname, type); + if (ctx->LHS) { + if (ctx->LHS[0] != '.') + strcat(bindname, "."); + strcat(bindname, ctx->LHS); + } + if (RHS[0] != '.') + strcat(bindname, "."); + strcat(bindname, RHS); + + if (rhs_list) + hesiod_free_list(context, rhs_list); + + return (bindname); +} + +/*% + * This is the core function. Given a hesiod (name, type), it + * returns an array of strings returned by the resolver. + */ +char ** +hesiod_resolve(void *context, const char *name, const char *type) { + struct hesiod_p *ctx = (struct hesiod_p *) context; + char *bindname = hesiod_to_bind(context, name, type); + char **retvec; + + if (bindname == NULL) + return (NULL); + if (init(ctx) == -1) { + free(bindname); + return (NULL); + } + + if ((retvec = get_txt_records(ctx, C_IN, bindname))) { + free(bindname); + return (retvec); + } + + if (errno != ENOENT) + return (NULL); + + retvec = get_txt_records(ctx, C_HS, bindname); + free(bindname); + return (retvec); +} + +void +hesiod_free_list(void *context, char **list) { + char **p; + + UNUSED(context); + + for (p = list; *p; p++) + free(*p); + free(list); +} + +/*% + * This function parses the /etc/hesiod.conf file + */ +static int +parse_config_file(struct hesiod_p *ctx, const char *filename) { + char *key, *data, *cp, **cpp; + char buf[MAXDNAME+7]; + FILE *fp; + + /* + * Clear the existing configuration variable, just in case + * they're set. + */ + if (ctx->RHS) + free(ctx->RHS); + if (ctx->LHS) + free(ctx->LHS); + ctx->RHS = ctx->LHS = 0; + + /* + * Now open and parse the file... + */ + if (!(fp = fopen(filename, "r"))) + return (-1); + + while (fgets(buf, sizeof(buf), fp) != NULL) { + cp = buf; + if (*cp == '#' || *cp == '\n' || *cp == '\r') + continue; + while(*cp == ' ' || *cp == '\t') + cp++; + key = cp; + while(*cp != ' ' && *cp != '\t' && *cp != '=') + cp++; + *cp++ = '\0'; + + while(*cp == ' ' || *cp == '\t' || *cp == '=') + cp++; + data = cp; + while(*cp != ' ' && *cp != '\n' && *cp != '\r') + cp++; + *cp++ = '\0'; + + if (strcmp(key, "lhs") == 0) + cpp = &ctx->LHS; + else if (strcmp(key, "rhs") == 0) + cpp = &ctx->RHS; + else + continue; + + *cpp = malloc(strlen(data) + 1); + if (!*cpp) { + errno = ENOMEM; + goto cleanup; + } + strcpy(*cpp, data); + } + fclose(fp); + return (0); + + cleanup: + fclose(fp); + if (ctx->RHS) + free(ctx->RHS); + if (ctx->LHS) + free(ctx->LHS); + ctx->RHS = ctx->LHS = 0; + return (-1); +} + +/*% + * Given a DNS class and a DNS name, do a lookup for TXT records, and + * return a list of them. + */ +static char ** +get_txt_records(struct hesiod_p *ctx, int class, const char *name) { + struct { + int type; /*%< RR type */ + int class; /*%< RR class */ + int dlen; /*%< len of data section */ + u_char *data; /*%< pointer to data */ + } rr; + HEADER *hp; + u_char qbuf[MAX_HESRESP], abuf[MAX_HESRESP]; + u_char *cp, *erdata, *eom; + char *dst, *edst, **list; + int ancount, qdcount; + int i, j, n, skip; + + /* + * Construct the query and send it. + */ + n = res_nmkquery(ctx->res, QUERY, name, class, T_TXT, NULL, 0, + NULL, qbuf, MAX_HESRESP); + if (n < 0) { + errno = EMSGSIZE; + return (NULL); + } + n = res_nsend(ctx->res, qbuf, n, abuf, MAX_HESRESP); + if (n < 0) { + errno = ECONNREFUSED; + return (NULL); + } + if (n < HFIXEDSZ) { + errno = EMSGSIZE; + return (NULL); + } + + /* + * OK, parse the result. + */ + hp = (HEADER *) abuf; + ancount = ntohs(hp->ancount); + qdcount = ntohs(hp->qdcount); + cp = abuf + sizeof(HEADER); + eom = abuf + n; + + /* Skip query, trying to get to the answer section which follows. */ + for (i = 0; i < qdcount; i++) { + skip = dn_skipname(cp, eom); + if (skip < 0 || cp + skip + QFIXEDSZ > eom) { + errno = EMSGSIZE; + return (NULL); + } + cp += skip + QFIXEDSZ; + } + + list = malloc((ancount + 1) * sizeof(char *)); + if (!list) { + errno = ENOMEM; + return (NULL); + } + j = 0; + for (i = 0; i < ancount; i++) { + skip = dn_skipname(cp, eom); + if (skip < 0) { + errno = EMSGSIZE; + goto cleanup; + } + cp += skip; + if (cp + 3 * INT16SZ + INT32SZ > eom) { + errno = EMSGSIZE; + goto cleanup; + } + rr.type = ns_get16(cp); + cp += INT16SZ; + rr.class = ns_get16(cp); + cp += INT16SZ + INT32SZ; /*%< skip the ttl, too */ + rr.dlen = ns_get16(cp); + cp += INT16SZ; + if (cp + rr.dlen > eom) { + errno = EMSGSIZE; + goto cleanup; + } + rr.data = cp; + cp += rr.dlen; + if (rr.class != class || rr.type != T_TXT) + continue; + if (!(list[j] = malloc(rr.dlen))) + goto cleanup; + dst = list[j++]; + edst = dst + rr.dlen; + erdata = rr.data + rr.dlen; + cp = rr.data; + while (cp < erdata) { + n = (unsigned char) *cp++; + if (cp + n > eom || dst + n > edst) { + errno = EMSGSIZE; + goto cleanup; + } + memcpy(dst, cp, n); + cp += n; + dst += n; + } + if (cp != erdata) { + errno = EMSGSIZE; + goto cleanup; + } + *dst = '\0'; + } + list[j] = NULL; + if (j == 0) { + errno = ENOENT; + goto cleanup; + } + return (list); + + cleanup: + for (i = 0; i < j; i++) + free(list[i]); + free(list); + return (NULL); +} + +struct __res_state * +__hesiod_res_get(void *context) { + struct hesiod_p *ctx = context; + + if (!ctx->res) { + struct __res_state *res; + res = (struct __res_state *)malloc(sizeof *res); + if (res == NULL) { + errno = ENOMEM; + return (NULL); + } + memset(res, 0, sizeof *res); + __hesiod_res_set(ctx, res, free); + } + + return (ctx->res); +} + +void +__hesiod_res_set(void *context, struct __res_state *res, + void (*free_res)(void *)) { + struct hesiod_p *ctx = context; + + if (ctx->res && ctx->free_res) { + res_nclose(ctx->res); + (*ctx->free_res)(ctx->res); + } + + ctx->res = res; + ctx->free_res = free_res; +} + +static int +init(struct hesiod_p *ctx) { + + if (!ctx->res && !__hesiod_res_get(ctx)) + return (-1); + + if (((ctx->res->options & RES_INIT) == 0U) && + (res_ninit(ctx->res) == -1)) + return (-1); + + return (0); +} diff --git a/contrib/bind-9.5.2/lib/bind/irs/hesiod_p.h b/contrib/bind-9.5.2/lib/bind/irs/hesiod_p.h new file mode 100644 index 0000000000..99da15d0cd --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/hesiod_p.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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: hesiod_p.h,v 1.3 2005/04/27 04:56:27 sra Exp $ + */ + +#ifndef _HESIOD_P_H_INCLUDED +#define _HESIOD_P_H_INCLUDED + +/** \file + * \brief + * hesiod_p.h -- private definitions for the hesiod library. + * + * \author + * This file is primarily maintained by tytso@mit.edu and ghudson@mit.edu. + */ + +#define DEF_RHS ".Athena.MIT.EDU" /*%< Defaults if HESIOD_CONF */ +#define DEF_LHS ".ns" /*%< file is not */ + /*%< present. */ +struct hesiod_p { + char * LHS; /*%< normally ".ns" */ + char * RHS; /*%< AKA the default hesiod domain */ + struct __res_state * res; /*%< resolver context */ + void (*free_res)(void *); + void (*res_set)(struct hesiod_p *, struct __res_state *, + void (*)(void *)); + struct __res_state * (*res_get)(struct hesiod_p *); +}; + +#define MAX_HESRESP 1024 + +#endif /*_HESIOD_P_H_INCLUDED*/ diff --git a/contrib/bind-9.5.2/lib/bind/irs/irp.c b/contrib/bind-9.5.2/lib/bind/irs/irp.c new file mode 100644 index 0000000000..15e7dbdf36 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/irp.c @@ -0,0 +1,583 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996, 1998 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: irp.c,v 1.9.394.2 2008/02/28 05:46:12 marka Exp $"; +#endif + +/* Imports */ + +#include "port_before.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "irs_p.h" +#include "irp_p.h" + +#include "port_after.h" + +/* Forward. */ + +static void irp_close(struct irs_acc *); + +#define LINEINCR 128 + +#if !defined(SUN_LEN) +#define SUN_LEN(su) \ + (sizeof (*(su)) - sizeof ((su)->sun_path) + strlen((su)->sun_path)) +#endif + + +/* Public */ + + +/* send errors to syslog if true. */ +int irp_log_errors = 1; + +/*% + * This module handles the irp module connection to irpd. + * + * The client expects a synchronous interface to functions like + * getpwnam(3), so we can't use the ctl_* i/o library on this end of + * the wire (it's used in the server). + */ + +/*% + * irs_acc *irs_irp_acc(const char *options); + * + * Initialize the irp module. + */ +struct irs_acc * +irs_irp_acc(const char *options) { + struct irs_acc *acc; + struct irp_p *irp; + + UNUSED(options); + + if (!(acc = memget(sizeof *acc))) { + errno = ENOMEM; + return (NULL); + } + memset(acc, 0x5e, sizeof *acc); + if (!(irp = memget(sizeof *irp))) { + errno = ENOMEM; + free(acc); + return (NULL); + } + irp->inlast = 0; + irp->incurr = 0; + irp->fdCxn = -1; + acc->private = irp; + +#ifdef WANT_IRS_GR + acc->gr_map = irs_irp_gr; +#else + acc->gr_map = NULL; +#endif +#ifdef WANT_IRS_PW + acc->pw_map = irs_irp_pw; +#else + acc->pw_map = NULL; +#endif + acc->sv_map = irs_irp_sv; + acc->pr_map = irs_irp_pr; + acc->ho_map = irs_irp_ho; + acc->nw_map = irs_irp_nw; + acc->ng_map = irs_irp_ng; + acc->close = irp_close; + return (acc); +} + + +int +irs_irp_connection_setup(struct irp_p *cxndata, int *warned) { + if (irs_irp_is_connected(cxndata)) { + return (0); + } else if (irs_irp_connect(cxndata) != 0) { + if (warned != NULL && !*warned) { + syslog(LOG_ERR, "irpd connection failed: %m\n"); + (*warned)++; + } + + return (-1); + } + + return (0); +} + +/*% + * int irs_irp_connect(void); + * + * Sets up the connection to the remote irpd server. + * + * Returns: + * + * 0 on success, -1 on failure. + * + */ +int +irs_irp_connect(struct irp_p *pvt) { + int flags; + struct sockaddr *addr; + struct sockaddr_in iaddr; +#ifndef NO_SOCKADDR_UN + struct sockaddr_un uaddr; +#endif + long ipaddr; + const char *irphost; + int code; + char text[256]; + int socklen = 0; + + if (pvt->fdCxn != -1) { + perror("fd != 1"); + return (-1); + } + +#ifndef NO_SOCKADDR_UN + memset(&uaddr, 0, sizeof uaddr); +#endif + memset(&iaddr, 0, sizeof iaddr); + + irphost = getenv(IRPD_HOST_ENV); + if (irphost == NULL) { + irphost = "127.0.0.1"; + } + +#ifndef NO_SOCKADDR_UN + if (irphost[0] == '/') { + addr = (struct sockaddr *)&uaddr; + strncpy(uaddr.sun_path, irphost, sizeof uaddr.sun_path); + uaddr.sun_family = AF_UNIX; + socklen = SUN_LEN(&uaddr); +#ifdef HAVE_SA_LEN + uaddr.sun_len = socklen; +#endif + } else +#endif + { + if (inet_pton(AF_INET, irphost, &ipaddr) != 1) { + errno = EADDRNOTAVAIL; + perror("inet_pton"); + return (-1); + } + + addr = (struct sockaddr *)&iaddr; + socklen = sizeof iaddr; +#ifdef HAVE_SA_LEN + iaddr.sin_len = socklen; +#endif + iaddr.sin_family = AF_INET; + iaddr.sin_port = htons(IRPD_PORT); + iaddr.sin_addr.s_addr = ipaddr; + } + + + pvt->fdCxn = socket(addr->sa_family, SOCK_STREAM, PF_UNSPEC); + if (pvt->fdCxn < 0) { + perror("socket"); + return (-1); + } + + if (connect(pvt->fdCxn, addr, socklen) != 0) { + perror("connect"); + return (-1); + } + + flags = fcntl(pvt->fdCxn, F_GETFL, 0); + if (flags < 0) { + close(pvt->fdCxn); + perror("close"); + return (-1); + } + +#if 0 + flags |= O_NONBLOCK; + if (fcntl(pvt->fdCxn, F_SETFL, flags) < 0) { + close(pvt->fdCxn); + perror("fcntl"); + return (-1); + } +#endif + + code = irs_irp_read_response(pvt, text, sizeof text); + if (code != IRPD_WELCOME_CODE) { + if (irp_log_errors) { + syslog(LOG_WARNING, "Connection failed: %s", text); + } + irs_irp_disconnect(pvt); + return (-1); + } + + return (0); +} + +/*% + * int irs_irp_is_connected(struct irp_p *pvt); + * + * Returns: + * + * Non-zero if streams are setup to remote. + * + */ + +int +irs_irp_is_connected(struct irp_p *pvt) { + return (pvt->fdCxn >= 0); +} + +/*% + * void + * irs_irp_disconnect(struct irp_p *pvt); + * + * Closes streams to remote. + */ + +void +irs_irp_disconnect(struct irp_p *pvt) { + if (pvt->fdCxn != -1) { + close(pvt->fdCxn); + pvt->fdCxn = -1; + } +} + + + +int +irs_irp_read_line(struct irp_p *pvt, char *buffer, int len) { + char *realstart = &pvt->inbuffer[0]; + char *p, *start, *end; + int spare; + int i; + int buffpos = 0; + int left = len - 1; + + while (left > 0) { + start = p = &pvt->inbuffer[pvt->incurr]; + end = &pvt->inbuffer[pvt->inlast]; + + while (p != end && *p != '\n') + p++; + + if (p == end) { + /* Found no newline so shift data down if necessary + * and append new data to buffer + */ + if (start > realstart) { + memmove(realstart, start, end - start); + pvt->inlast = end - start; + start = realstart; + pvt->incurr = 0; + end = &pvt->inbuffer[pvt->inlast]; + } + + spare = sizeof (pvt->inbuffer) - pvt->inlast; + + p = end; + i = read(pvt->fdCxn, end, spare); + if (i < 0) { + close(pvt->fdCxn); + pvt->fdCxn = -1; + return (buffpos > 0 ? buffpos : -1); + } else if (i == 0) { + return (buffpos); + } + + end += i; + pvt->inlast += i; + + while (p != end && *p != '\n') + p++; + } + + if (p == end) { + /* full buffer and still no newline */ + i = sizeof pvt->inbuffer; + } else { + /* include newline */ + i = p - start + 1; + } + + if (i > left) + i = left; + memcpy(buffer + buffpos, start, i); + pvt->incurr += i; + buffpos += i; + buffer[buffpos] = '\0'; + + if (p != end) { + left = 0; + } else { + left -= i; + } + } + +#if 0 + fprintf(stderr, "read line: %s\n", buffer); +#endif + return (buffpos); +} + +/*% + * int irp_read_response(struct irp_p *pvt); + * + * Returns: + * + * The number found at the beginning of the line read from + * FP. 0 on failure(0 is not a legal response code). The + * rest of the line is discarded. + * + */ + +int +irs_irp_read_response(struct irp_p *pvt, char *text, size_t textlen) { + char line[1024]; + int code; + char *p; + + if (irs_irp_read_line(pvt, line, sizeof line) <= 0) { + return (0); + } + + p = strchr(line, '\n'); + if (p == NULL) { + return (0); + } + + if (sscanf(line, "%d", &code) != 1) { + code = 0; + } else if (text != NULL && textlen > 0U) { + p = line; + while (isspace((unsigned char)*p)) p++; + while (isdigit((unsigned char)*p)) p++; + while (isspace((unsigned char)*p)) p++; + strncpy(text, p, textlen - 1); + p[textlen - 1] = '\0'; + } + + return (code); +} + +/*% + * char *irp_read_body(struct irp_p *pvt, size_t *size); + * + * Read in the body of a response. Terminated by a line with + * just a dot on it. Lines should be terminated with a CR-LF + * sequence, but we're nt piccky if the CR is missing. + * No leading dot escaping is done as the protcol doesn't + * use leading dots anywhere. + * + * Returns: + * + * Pointer to null-terminated buffer allocated by memget. + * *SIZE is set to the length of the buffer. + * + */ + +char * +irs_irp_read_body(struct irp_p *pvt, size_t *size) { + char line[1024]; + u_int linelen; + size_t len = LINEINCR; + char *buffer = memget(len); + int idx = 0; + + if (buffer == NULL) + return (NULL); + + for (;;) { + if (irs_irp_read_line(pvt, line, sizeof line) <= 0 || + strchr(line, '\n') == NULL) + goto death; + + linelen = strlen(line); + + if (line[linelen - 1] != '\n') + goto death; + + /* We're not strict about missing \r. Should we be?? */ + if (linelen > 2 && line[linelen - 2] == '\r') { + line[linelen - 2] = '\n'; + line[linelen - 1] = '\0'; + linelen--; + } + + if (linelen == 2 && line[0] == '.') { + *size = len; + buffer[idx] = '\0'; + + return (buffer); + } + + if (linelen > (len - (idx + 1))) { + char *p = memget(len + LINEINCR); + + if (p == NULL) + goto death; + memcpy(p, buffer, len); + memput(buffer, len); + buffer = p; + len += LINEINCR; + } + + memcpy(buffer + idx, line, linelen); + idx += linelen; + } + death: + memput(buffer, len); + return (NULL); +} + +/*% + * int irs_irp_get_full_response(struct irp_p *pvt, int *code, + * char **body, size_t *bodylen); + * + * Gets the response to a command. If the response indicates + * there's a body to follow(code % 10 == 1), then the + * body buffer is allcoated with memget and stored in + * *BODY. The length of the allocated body buffer is stored + * in *BODY. The caller must give the body buffer back to + * memput when done. The results code is stored in *CODE. + * + * Returns: + * + * 0 if a result was read. -1 on some sort of failure. + * + */ + +int +irs_irp_get_full_response(struct irp_p *pvt, int *code, char *text, + size_t textlen, char **body, size_t *bodylen) { + int result = irs_irp_read_response(pvt, text, textlen); + + *body = NULL; + + if (result == 0) { + return (-1); + } + + *code = result; + + /* Code that matches 2xx is a good result code. + * Code that matches xx1 means there's a response body coming. + */ + if ((result / 100) == 2 && (result % 10) == 1) { + *body = irs_irp_read_body(pvt, bodylen); + if (*body == NULL) { + return (-1); + } + } + + return (0); +} + +/*% + * int irs_irp_send_command(struct irp_p *pvt, const char *fmt, ...); + * + * Sends command to remote connected via the PVT + * structure. FMT and args after it are fprintf-like + * arguments for formatting. + * + * Returns: + * + * 0 on success, -1 on failure. + */ + +int +irs_irp_send_command(struct irp_p *pvt, const char *fmt, ...) { + va_list ap; + char buffer[1024]; + int pos = 0; + int i, todo; + + + if (pvt->fdCxn < 0) { + return (-1); + } + + va_start(ap, fmt); + (void) vsprintf(buffer, fmt, ap); + todo = strlen(buffer); + va_end(ap); + if (todo > (int)sizeof(buffer) - 3) { + syslog(LOG_CRIT, "memory overrun in irs_irp_send_command()"); + exit(1); + } + strcat(buffer, "\r\n"); + todo = strlen(buffer); + + while (todo > 0) { + i = write(pvt->fdCxn, buffer + pos, todo); +#if 0 + /* XXX brister */ + fprintf(stderr, "Wrote: \""); + fwrite(buffer + pos, sizeof (char), todo, stderr); + fprintf(stderr, "\"\n"); +#endif + if (i < 0) { + close(pvt->fdCxn); + pvt->fdCxn = -1; + return (-1); + } + todo -= i; + } + + return (0); +} + + +/* Methods */ + +/*% + * void irp_close(struct irs_acc *this) + * + */ + +static void +irp_close(struct irs_acc *this) { + struct irp_p *irp = (struct irp_p *)this->private; + + if (irp != NULL) { + irs_irp_disconnect(irp); + memput(irp, sizeof *irp); + } + + memput(this, sizeof *this); +} + + + + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/irp_gr.c b/contrib/bind-9.5.2/lib/bind/irs/irp_gr.c new file mode 100644 index 0000000000..1f40e76022 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/irp_gr.c @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright(c) 1996, 1998 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: irp_gr.c,v 1.4 2005/04/27 04:56:27 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* extern */ + +#include "port_before.h" + +#ifndef WANT_IRS_PW +static int __bind_irs_gr_unneeded; +#else + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "irs_p.h" +#include "lcl_p.h" +#include "irp_p.h" + +#include "port_after.h" + + +/* Types. */ + +/*! \file + * \brief + * Module for the getnetgrent(3) family to use when connected to a + * remote irp daemon. + * \brief + * See irpd.c for justification of caching done here. + * + */ + +struct pvt { + struct irp_p *girpdata; /*%< global IRP data */ + int warned; + struct group group; +}; + +/* Forward. */ + +static void gr_close(struct irs_gr *); +static struct group * gr_next(struct irs_gr *); +static struct group * gr_byname(struct irs_gr *, const char *); +static struct group * gr_bygid(struct irs_gr *, gid_t); +static void gr_rewind(struct irs_gr *); +static void gr_minimize(struct irs_gr *); + +/* Private */ +static void free_group(struct group *gr); + + +/* Public. */ + +/*% + * Initialize the group sub-module. + * + */ + +struct irs_gr * +irs_irp_gr(struct irs_acc *this) { + struct irs_gr *gr; + struct pvt *pvt; + + if (!(gr = memget(sizeof *gr))) { + errno = ENOMEM; + return (NULL); + } + memset(gr, 0x0, sizeof *gr); + + if (!(pvt = memget(sizeof *pvt))) { + memput(gr, sizeof *gr); + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0x0, sizeof *pvt); + pvt->girpdata = this->private; + + gr->private = pvt; + gr->close = gr_close; + gr->next = gr_next; + gr->byname = gr_byname; + gr->bygid = gr_bygid; + gr->rewind = gr_rewind; + gr->list = make_group_list; + gr->minimize = gr_minimize; + return (gr); +} + +/* Methods. */ + +/*% + * Close the sub-module. + * + */ + +static void +gr_close(struct irs_gr *this) { + struct pvt *pvt = (struct pvt *)this->private; + + gr_minimize(this); + + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +/*% + * Gets the next group out of the cached data and returns it. + * + */ + +static struct group * +gr_next(struct irs_gr *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct group *gr = &pvt->group; + char *body; + size_t bodylen; + int code; + char text[256]; + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return (NULL); + } + + if (irs_irp_send_command(pvt->girpdata, "getgrent") != 0) { + return (NULL); + } + + if (irs_irp_get_full_response(pvt->girpdata, &code, + text, sizeof text, + &body, &bodylen) != 0) { + if (irp_log_errors) { + syslog(LOG_WARNING, "getgrent failed: %s", text); + } + return (NULL); + } + + if (code == IRPD_GETGROUP_OK) { + free_group(gr); + if (irp_unmarshall_gr(gr, body) != 0) { + gr = NULL; + } + } else { + gr = NULL; + } + + if (body != NULL) { + memput(body, bodylen); + } + + return (gr); +} + +/*% + * Gets a group by name from irpd and returns it. + * + */ + +static struct group * +gr_byname(struct irs_gr *this, const char *name) { + struct pvt *pvt = (struct pvt *)this->private; + struct group *gr = &pvt->group; + char *body; + size_t bodylen; + int code; + char text[256]; + + + if (gr->gr_name != NULL && strcmp(name, gr->gr_name) == 0) { + return (gr); + } + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return (NULL); + } + + if (irs_irp_send_command(pvt->girpdata, "getgrnam %s", name) != 0) + return (NULL); + + if (irs_irp_get_full_response(pvt->girpdata, &code, + text, sizeof text, + &body, &bodylen) != 0) { + return (NULL); + } + + if (code == IRPD_GETGROUP_OK) { + free_group(gr); + if (irp_unmarshall_gr(gr, body) != 0) { + gr = NULL; + } + } else { + gr = NULL; + } + + if (body != NULL) { + memput(body, bodylen); + } + + return (gr); +} + +/*% + * Gets a group by gid from irpd and returns it. + * + */ + +static struct group * +gr_bygid(struct irs_gr *this, gid_t gid) { + struct pvt *pvt = (struct pvt *)this->private; + struct group *gr = &pvt->group; + char *body; + size_t bodylen; + int code; + char text[256]; + + if (gr->gr_name != NULL && (gid_t)gr->gr_gid == gid) { + return (gr); + } + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return (NULL); + } + + if (irs_irp_send_command(pvt->girpdata, "getgrgid %d", gid) != 0) + return (NULL); + + if (irs_irp_get_full_response(pvt->girpdata, &code, + text, sizeof text, + &body, &bodylen) != 0) { + return (NULL); + } + + if (code == IRPD_GETGROUP_OK) { + free_group(gr); + if (irp_unmarshall_gr(gr, body) != 0) { + gr = NULL; + } + } else { + gr = NULL; + } + + if (body != NULL) { + memput(body, bodylen); + } + + return (gr); +} + +/*% + * void gr_rewind(struct irs_gr *this) + * + */ + +static void +gr_rewind(struct irs_gr *this) { + struct pvt *pvt = (struct pvt *)this->private; + char text[256]; + int code; + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return; + } + + if (irs_irp_send_command(pvt->girpdata, "setgrent") != 0) { + return; + } + + code = irs_irp_read_response(pvt->girpdata, text, sizeof text); + if (code != IRPD_GETGROUP_SETOK) { + if (irp_log_errors) { + syslog(LOG_WARNING, "setgrent failed: %s", text); + } + } + + return; +} + +/*% + * Frees up cached data and disconnects(if necessary) from the remote. + * + */ + +static void +gr_minimize(struct irs_gr *this) { + struct pvt *pvt = (struct pvt *)this->private; + + free_group(&pvt->group); + irs_irp_disconnect(pvt->girpdata); +} + +/* Private. */ + +/*% + * static void free_group(struct group *gr); + * + * Deallocate all the memory irp_unmarshall_gr allocated. + * + */ + +static void +free_group(struct group *gr) { + char **p; + + if (gr == NULL) + return; + + if (gr->gr_name != NULL) + free(gr->gr_name); + + if (gr->gr_passwd != NULL) + free(gr->gr_passwd); + + for (p = gr->gr_mem ; p != NULL && *p != NULL ; p++) + free(*p); + + if (gr->gr_mem) + free(gr->gr_mem); + + if (p != NULL) + free(p); +} + + +#endif /* WANT_IRS_GR */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/irp_ho.c b/contrib/bind-9.5.2/lib/bind/irs/irp_ho.c new file mode 100644 index 0000000000..d4ce5c3bbe --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/irp_ho.c @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996,1998 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: irp_ho.c,v 1.3 2005/04/27 04:56:28 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* Imports. */ + +#include "port_before.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "irs_p.h" +#include "dns_p.h" +#include "irp_p.h" + +#include "port_after.h" + +/* Definitions. */ + +#define MAXALIASES 35 +#define MAXADDRS 35 +#define Max(a,b) ((a) > (b) ? (a) : (b)) + + +struct pvt { + struct irp_p *girpdata; + int warned; + struct hostent host; +}; + +/* Forward. */ + +static void ho_close(struct irs_ho *this); +static struct hostent * ho_byname(struct irs_ho *this, const char *name); +static struct hostent * ho_byname2(struct irs_ho *this, const char *name, + int af); +static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr, + int len, int af); +static struct hostent * ho_next(struct irs_ho *this); +static void ho_rewind(struct irs_ho *this); +static void ho_minimize(struct irs_ho *this); + +static void free_host(struct hostent *ho); +static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name, + const struct addrinfo *pai); + +/* Public. */ + +/*% + * struct irs_ho * irs_irp_ho(struct irs_acc *this) + * + * Notes: + * + * Initializes the irp_ho module. + * + */ + +struct irs_ho * +irs_irp_ho(struct irs_acc *this) { + struct irs_ho *ho; + struct pvt *pvt; + + if (!(ho = memget(sizeof *ho))) { + errno = ENOMEM; + return (NULL); + } + memset(ho, 0x0, sizeof *ho); + + if (!(pvt = memget(sizeof *pvt))) { + memput(ho, sizeof *ho); + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + pvt->girpdata = this->private; + + ho->private = pvt; + ho->close = ho_close; + ho->byname = ho_byname; + ho->byname2 = ho_byname2; + ho->byaddr = ho_byaddr; + ho->next = ho_next; + ho->rewind = ho_rewind; + ho->minimize = ho_minimize; + ho->addrinfo = ho_addrinfo; + + return (ho); +} + +/* Methods. */ + +/*% + * Closes down the module. + * + */ + +static void +ho_close(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + + ho_minimize(this); + + free_host(&pvt->host); + + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + + + +/* + * struct hostent * ho_byname(struct irs_ho *this, const char *name) + * + */ + +static struct hostent * +ho_byname(struct irs_ho *this, const char *name) { + return (ho_byname2(this, name, AF_INET)); +} + + + + + +/* + * struct hostent * ho_byname2(struct irs_ho *this, const char *name, int af) + * + */ + +static struct hostent * +ho_byname2(struct irs_ho *this, const char *name, int af) { + struct pvt *pvt = (struct pvt *)this->private; + struct hostent *ho = &pvt->host; + char *body = NULL; + size_t bodylen; + int code; + char text[256]; + + if (ho->h_name != NULL && + strcmp(name, ho->h_name) == 0 && + af == ho->h_addrtype) { + return (ho); + } + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return (NULL); + } + + if (irs_irp_send_command(pvt->girpdata, "gethostbyname2 %s %s", + name, ADDR_T_STR(af)) != 0) + return (NULL); + + if (irs_irp_get_full_response(pvt->girpdata, &code, + text, sizeof text, + &body, &bodylen) != 0) { + return (NULL); + } + + if (code == IRPD_GETHOST_OK) { + free_host(ho); + if (irp_unmarshall_ho(ho, body) != 0) { + ho = NULL; + } + } else { + ho = NULL; + } + + if (body != NULL) { + memput(body, bodylen); + } + + return (ho); +} + + + +/* + * struct hostent * ho_byaddr(struct irs_ho *this, const void *addr, + * int len, int af) + * + */ + +static struct hostent * +ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) { + struct pvt *pvt = (struct pvt *)this->private; + struct hostent *ho = &pvt->host; + char *body = NULL; + size_t bodylen; + int code; + char **p; + char paddr[MAXPADDRSIZE]; + char text[256]; + + if (ho->h_name != NULL && + af == ho->h_addrtype && + len == ho->h_length) { + for (p = ho->h_addr_list ; *p != NULL ; p++) { + if (memcmp(*p, addr, len) == 0) + return (ho); + } + } + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return (NULL); + } + + if (inet_ntop(af, addr, paddr, sizeof paddr) == NULL) { + return (NULL); + } + + if (irs_irp_send_command(pvt->girpdata, "gethostbyaddr %s %s", + paddr, ADDR_T_STR(af)) != 0) { + return (NULL); + } + + if (irs_irp_get_full_response(pvt->girpdata, &code, + text, sizeof text, + &body, &bodylen) != 0) { + return (NULL); + } + + if (code == IRPD_GETHOST_OK) { + free_host(ho); + if (irp_unmarshall_ho(ho, body) != 0) { + ho = NULL; + } + } else { + ho = NULL; + } + + if (body != NULL) { + memput(body, bodylen); + } + + return (ho); +} + +/*% + * The implementation for gethostent(3). The first time it's + * called all the data is pulled from the remote(i.e. what + * the maximum number of gethostent(3) calls would return) + * and that data is cached. + * + */ + +static struct hostent * +ho_next(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct hostent *ho = &pvt->host; + char *body; + size_t bodylen; + int code; + char text[256]; + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return (NULL); + } + + if (irs_irp_send_command(pvt->girpdata, "gethostent") != 0) { + return (NULL); + } + + if (irs_irp_get_full_response(pvt->girpdata, &code, + text, sizeof text, + &body, &bodylen) != 0) { + return (NULL); + } + + if (code == IRPD_GETHOST_OK) { + free_host(ho); + if (irp_unmarshall_ho(ho, body) != 0) { + ho = NULL; + } + } else { + ho = NULL; + } + + if (body != NULL) { + memput(body, bodylen); + } + + return (ho); +} + +/*% + * void ho_rewind(struct irs_ho *this) + * + */ + +static void +ho_rewind(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + char text[256]; + int code; + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return; + } + + if (irs_irp_send_command(pvt->girpdata, "sethostent") != 0) { + return; + } + + code = irs_irp_read_response(pvt->girpdata, text, sizeof text); + if (code != IRPD_GETHOST_SETOK) { + if (irp_log_errors) { + syslog(LOG_WARNING, "sethostent failed: %s", text); + } + } + + return; +} + +/*% + * void ho_minimize(struct irs_ho *this) + * + */ + +static void +ho_minimize(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + + free_host(&pvt->host); + + irs_irp_disconnect(pvt->girpdata); +} + +/*% + * void free_host(struct hostent *ho) + * + */ + +static void +free_host(struct hostent *ho) { + char **p; + + if (ho == NULL) { + return; + } + + if (ho->h_name != NULL) + free(ho->h_name); + + if (ho->h_aliases != NULL) { + for (p = ho->h_aliases ; *p != NULL ; p++) + free(*p); + free(ho->h_aliases); + } + + if (ho->h_addr_list != NULL) { + for (p = ho->h_addr_list ; *p != NULL ; p++) + free(*p); + free(ho->h_addr_list); + } +} + +/* dummy */ +static struct addrinfo * +ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai) +{ + UNUSED(this); + UNUSED(name); + UNUSED(pai); + return(NULL); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/irp_ng.c b/contrib/bind-9.5.2/lib/bind/irs/irp_ng.c new file mode 100644 index 0000000000..1af862cab4 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/irp_ng.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996, 1998 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: irp_ng.c,v 1.4 2006/12/07 04:46:27 marka Exp $"; +#endif + +/* Imports */ + +#include "port_before.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "irs_p.h" +#include "irp_p.h" + +#include "port_after.h" + +/* Definitions */ + +struct pvt { + struct irp_p *girpdata; + int warned; +}; + + +/* Forward */ + +static void ng_rewind(struct irs_ng *, const char*); +static void ng_close(struct irs_ng *); +static int ng_next(struct irs_ng *, const char **, const char **, + const char **); +static int ng_test(struct irs_ng *, const char *, + const char *, const char *, + const char *); +static void ng_minimize(struct irs_ng *); + + +/* Public */ + +/*% + * Intialize the irp netgroup module. + * + */ + +struct irs_ng * +irs_irp_ng(struct irs_acc *this) { + struct irs_ng *ng; + struct pvt *pvt; + + if (!(ng = memget(sizeof *ng))) { + errno = ENOMEM; + return (NULL); + } + memset(ng, 0x5e, sizeof *ng); + + if (!(pvt = memget(sizeof *pvt))) { + memput(ng, sizeof *ng); + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + pvt->girpdata = this->private; + + ng->private = pvt; + ng->close = ng_close; + ng->next = ng_next; + ng->test = ng_test; + ng->rewind = ng_rewind; + ng->minimize = ng_minimize; + return (ng); +} + +/* Methods */ + + + +/* + * void ng_close(struct irs_ng *this) + * + */ + +static void +ng_close(struct irs_ng *this) { + struct pvt *pvt = (struct pvt *)this->private; + + ng_minimize(this); + + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + + + + +/* + * void ng_rewind(struct irs_ng *this, const char *group) + * + * + */ + +static void +ng_rewind(struct irs_ng *this, const char *group) { + struct pvt *pvt = (struct pvt *)this->private; + char text[256]; + int code; + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return; + } + + if (irs_irp_send_command(pvt->girpdata, + "setnetgrent %s", group) != 0) { + return; + } + + code = irs_irp_read_response(pvt->girpdata, text, sizeof text); + if (code != IRPD_GETNETGR_SETOK) { + if (irp_log_errors) { + syslog(LOG_WARNING, "setnetgrent(%s) failed: %s", + group, text); + } + } + + return; +} + +/* + * Get the next netgroup item from the cache. + * + */ + +static int +ng_next(struct irs_ng *this, const char **host, const char **user, + const char **domain) +{ + struct pvt *pvt = (struct pvt *)this->private; + int code; + char *body = NULL; + size_t bodylen; + int rval = 0; + char text[256]; + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return (0); + } + + if (irs_irp_send_command(pvt->girpdata, "getnetgrent") != 0) + return (0); + + if (irs_irp_get_full_response(pvt->girpdata, &code, + text, sizeof text, + &body, &bodylen) != 0) { + return (0); + } + + if (code == IRPD_GETNETGR_OK) { + if (irp_unmarshall_ng(host, user, domain, body) == 0) { + rval = 1; + } + } + + if (body != NULL) { + memput(body, bodylen); + } + + return (rval); +} + +/* + * Search for a match in a netgroup. + * + */ + +static int +ng_test(struct irs_ng *this, const char *name, + const char *host, const char *user, const char *domain) +{ + struct pvt *pvt = (struct pvt *)this->private; + char *body = NULL; + size_t bodylen = 0; + int code; + char text[256]; + int rval = 0; + + UNUSED(name); + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return (0); + } + + if (irp_marshall_ng(host, user, domain, &body, &bodylen) != 0) { + return (0); + } + + if (irs_irp_send_command(pvt->girpdata, "innetgr %s", body) == 0) { + code = irs_irp_read_response(pvt->girpdata, text, sizeof text); + if (code == IRPD_GETNETGR_MATCHES) { + rval = 1; + } + } + + memput(body, bodylen); + + return (rval); +} + + + + +/* + * void ng_minimize(struct irs_ng *this) + * + */ + +static void +ng_minimize(struct irs_ng *this) { + struct pvt *pvt = (struct pvt *)this->private; + + irs_irp_disconnect(pvt->girpdata); +} + + + + +/* Private */ + + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/irp_nw.c b/contrib/bind-9.5.2/lib/bind/irs/irp_nw.c new file mode 100644 index 0000000000..eb4654f9b9 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/irp_nw.c @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996,1998 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: irp_nw.c,v 1.4 2006/03/09 23:57:56 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#if 0 + +#endif + +/* Imports */ + +#include "port_before.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "irs_p.h" +#include "lcl_p.h" +#include "irp_p.h" + +#include "port_after.h" + +#define MAXALIASES 35 +#define MAXADDRSIZE 4 + +struct pvt { + struct irp_p *girpdata; + int warned; + struct nwent net; +}; + +/* Forward */ + +static void nw_close(struct irs_nw *); +static struct nwent * nw_byname(struct irs_nw *, const char *, int); +static struct nwent * nw_byaddr(struct irs_nw *, void *, int, int); +static struct nwent * nw_next(struct irs_nw *); +static void nw_rewind(struct irs_nw *); +static void nw_minimize(struct irs_nw *); + +static void free_nw(struct nwent *nw); + + +/* Public */ + +/*% + * struct irs_nw * irs_irp_nw(struct irs_acc *this) + * + */ + +struct irs_nw * +irs_irp_nw(struct irs_acc *this) { + struct irs_nw *nw; + struct pvt *pvt; + + if (!(pvt = memget(sizeof *pvt))) { + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + + if (!(nw = memget(sizeof *nw))) { + memput(pvt, sizeof *pvt); + errno = ENOMEM; + return (NULL); + } + memset(nw, 0x0, sizeof *nw); + pvt->girpdata = this->private; + + nw->private = pvt; + nw->close = nw_close; + nw->byname = nw_byname; + nw->byaddr = nw_byaddr; + nw->next = nw_next; + nw->rewind = nw_rewind; + nw->minimize = nw_minimize; + return (nw); +} + +/* Methods */ + +/*% + * void nw_close(struct irs_nw *this) + * + */ + +static void +nw_close(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + nw_minimize(this); + + free_nw(&pvt->net); + + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +/*% + * struct nwent * nw_byaddr(struct irs_nw *this, void *net, + * int length, int type) + * + */ + +static struct nwent * +nw_byaddr(struct irs_nw *this, void *net, int length, int type) { + struct pvt *pvt = (struct pvt *)this->private; + struct nwent *nw = &pvt->net; + char *body = NULL; + size_t bodylen; + int code; + char paddr[24]; /*%< bigenough for ip4 w/ cidr spec. */ + char text[256]; + + if (inet_net_ntop(type, net, length, paddr, sizeof paddr) == NULL) { + return (NULL); + } + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return (NULL); + } + + if (irs_irp_send_command(pvt->girpdata, "getnetbyaddr %s %s", + paddr, ADDR_T_STR(type)) != 0) + return (NULL); + + if (irs_irp_get_full_response(pvt->girpdata, &code, + text, sizeof text, + &body, &bodylen) != 0) { + return (NULL); + } + + if (code == IRPD_GETNET_OK) { + free_nw(nw); + if (irp_unmarshall_nw(nw, body) != 0) { + nw = NULL; + } + } else { + nw = NULL; + } + + if (body != NULL) { + memput(body, bodylen); + } + + return (nw); +} + +/*% + * struct nwent * nw_byname(struct irs_nw *this, const char *name, int type) + * + */ + +static struct nwent * +nw_byname(struct irs_nw *this, const char *name, int type) { + struct pvt *pvt = (struct pvt *)this->private; + struct nwent *nw = &pvt->net; + char *body = NULL; + size_t bodylen; + int code; + char text[256]; + + if (nw->n_name != NULL && + strcmp(name, nw->n_name) == 0 && + nw->n_addrtype == type) { + return (nw); + } + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return (NULL); + } + + if (irs_irp_send_command(pvt->girpdata, "getnetbyname %s", name) != 0) + return (NULL); + + if (irs_irp_get_full_response(pvt->girpdata, &code, + text, sizeof text, + &body, &bodylen) != 0) { + return (NULL); + } + + if (code == IRPD_GETNET_OK) { + free_nw(nw); + if (irp_unmarshall_nw(nw, body) != 0) { + nw = NULL; + } + } else { + nw = NULL; + } + + if (body != NULL) { + memput(body, bodylen); + } + + return (nw); +} + +/*% + * void nw_rewind(struct irs_nw *this) + * + */ + +static void +nw_rewind(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + char text[256]; + int code; + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return; + } + + if (irs_irp_send_command(pvt->girpdata, "setnetent") != 0) { + return; + } + + code = irs_irp_read_response(pvt->girpdata, text, sizeof text); + if (code != IRPD_GETNET_SETOK) { + if (irp_log_errors) { + syslog(LOG_WARNING, "setnetent failed: %s", text); + } + } + + return; +} + +/*% + * Prepares the cache if necessary and returns the first, or + * next item from it. + */ + +static struct nwent * +nw_next(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct nwent *nw = &pvt->net; + char *body; + size_t bodylen; + int code; + char text[256]; + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return (NULL); + } + + if (irs_irp_send_command(pvt->girpdata, "getnetent") != 0) { + return (NULL); + } + + if (irs_irp_get_full_response(pvt->girpdata, &code, + text, sizeof text, + &body, &bodylen) != 0) { + return (NULL); + } + + if (code == IRPD_GETNET_OK) { + free_nw(nw); + if (irp_unmarshall_nw(nw, body) != 0) { + nw = NULL; + } + } else { + nw = NULL; + } + + if (body != NULL) + memput(body, bodylen); + return (nw); +} + +/*% + * void nw_minimize(struct irs_nw *this) + * + */ + +static void +nw_minimize(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + irs_irp_disconnect(pvt->girpdata); +} + + + + +/* private. */ + +/*% + * deallocate all the memory irp_unmarshall_pw allocated. + * + */ + +static void +free_nw(struct nwent *nw) { + char **p; + + if (nw == NULL) + return; + + if (nw->n_name != NULL) + free(nw->n_name); + + if (nw->n_aliases != NULL) { + for (p = nw->n_aliases ; *p != NULL ; p++) { + free(*p); + } + free(nw->n_aliases); + } + + if (nw->n_addr != NULL) + free(nw->n_addr); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/irp_p.h b/contrib/bind-9.5.2/lib/bind/irs/irp_p.h new file mode 100644 index 0000000000..4f943f81bd --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/irp_p.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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: irp_p.h,v 1.5 2005/04/27 04:56:28 sra Exp $ + */ + +#ifndef _IRP_P_H_INCLUDED +#define _IRP_P_H_INCLUDED + +#include + +struct irp_p { + char inbuffer[1024]; + int inlast; /*%< index of one past the last char in buffer */ + int incurr; /*%< index of the next char to be read from buffer */ + int fdCxn; +}; + +/* + * Externs. + */ + +extern struct irs_acc * irs_irp_acc __P((const char *)); +extern struct irs_gr * irs_irp_gr __P((struct irs_acc *)); +extern struct irs_pw * irs_irp_pw __P((struct irs_acc *)); +extern struct irs_sv * irs_irp_sv __P((struct irs_acc *)); +extern struct irs_pr * irs_irp_pr __P((struct irs_acc *)); +extern struct irs_ho * irs_irp_ho __P((struct irs_acc *)); +extern struct irs_nw * irs_irp_nw __P((struct irs_acc *)); +extern struct irs_ng * irs_irp_ng __P((struct irs_acc *)); + +int irs_irp_connect(struct irp_p *pvt); +int irs_irp_is_connected(struct irp_p *pvt); +void irs_irp_disconnect(struct irp_p *pvt); +int irs_irp_read_response(struct irp_p *pvt, char *text, size_t textlen); +char *irs_irp_read_body(struct irp_p *pvt, size_t *size); +int irs_irp_get_full_response(struct irp_p *pvt, int *code, + char *text, size_t textlen, + char **body, size_t *bodylen); + +extern int irp_log_errors; + +#endif + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/irp_pr.c b/contrib/bind-9.5.2/lib/bind/irs/irp_pr.c new file mode 100644 index 0000000000..ea876e8281 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/irp_pr.c @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: irp_pr.c,v 1.3 2005/04/27 04:56:29 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* extern */ + +#include "port_before.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "irs_p.h" +#include "lcl_p.h" +#include "irp_p.h" + +#include "port_after.h" + + +#define MAXALIASES 35 + +/* Types */ + +struct pvt { + struct irp_p *girpdata; + int warned; + struct protoent proto; +}; + +/* Forward */ + +static void pr_close(struct irs_pr *); +static struct protoent * pr_next(struct irs_pr *); +static struct protoent * pr_byname(struct irs_pr *, const char *); +static struct protoent * pr_bynumber(struct irs_pr *, int); +static void pr_rewind(struct irs_pr *); +static void pr_minimize(struct irs_pr *); + +static void free_proto(struct protoent *pr); + +/* Public */ + +/*% + * struct irs_pr * irs_irp_pr(struct irs_acc *this) + * + */ + +struct irs_pr * +irs_irp_pr(struct irs_acc *this) { + struct irs_pr *pr; + struct pvt *pvt; + + if (!(pr = memget(sizeof *pr))) { + errno = ENOMEM; + return (NULL); + } + memset(pr, 0x0, sizeof *pr); + + if (!(pvt = memget(sizeof *pvt))) { + memput(pr, sizeof *pr); + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + pvt->girpdata = this->private; + + pr->private = pvt; + pr->close = pr_close; + pr->byname = pr_byname; + pr->bynumber = pr_bynumber; + pr->next = pr_next; + pr->rewind = pr_rewind; + pr->minimize = pr_minimize; + return (pr); +} + +/* Methods */ + +/*% + * void pr_close(struct irs_pr *this) + * + */ + +static void +pr_close(struct irs_pr *this) { + struct pvt *pvt = (struct pvt *)this->private; + + pr_minimize(this); + + free_proto(&pvt->proto); + + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +/*% + * struct protoent * pr_byname(struct irs_pr *this, const char *name) + * + */ + +static struct protoent * +pr_byname(struct irs_pr *this, const char *name) { + struct pvt *pvt = (struct pvt *)this->private; + struct protoent *pr = &pvt->proto; + char *body = NULL; + size_t bodylen; + int code; + int i; + char text[256]; + + if (pr->p_name != NULL && strcmp(name, pr->p_name) == 0) { + return (pr); + } + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return (NULL); + } + + i = irs_irp_send_command(pvt->girpdata, "getprotobyname %s", name); + if (i != 0) + return (NULL); + + if (irs_irp_get_full_response(pvt->girpdata, &code, + text, sizeof text, + &body, &bodylen) != 0) { + return (NULL); + } + + if (code == IRPD_GETPROTO_OK) { + free_proto(pr); + if (irp_unmarshall_pr(pr, body) != 0) { + pr = NULL; + } + } else { + pr = NULL; + } + + if (body != NULL) { + memput(body, bodylen); + } + + return (pr); +} + +/*% + * struct protoent * pr_bynumber(struct irs_pr *this, int proto) + * + */ + +static struct protoent * +pr_bynumber(struct irs_pr *this, int proto) { + struct pvt *pvt = (struct pvt *)this->private; + struct protoent *pr = &pvt->proto; + char *body = NULL; + size_t bodylen; + int code; + int i; + char text[256]; + + if (pr->p_name != NULL && proto == pr->p_proto) { + return (pr); + } + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return (NULL); + } + + i = irs_irp_send_command(pvt->girpdata, "getprotobynumber %d", proto); + if (i != 0) + return (NULL); + + if (irs_irp_get_full_response(pvt->girpdata, &code, + text, sizeof text, + &body, &bodylen) != 0) { + return (NULL); + } + + if (code == IRPD_GETPROTO_OK) { + free_proto(pr); + if (irp_unmarshall_pr(pr, body) != 0) { + pr = NULL; + } + } else { + pr = NULL; + } + + if (body != NULL) { + memput(body, bodylen); + } + + return (pr); +} + +/*% + * void pr_rewind(struct irs_pr *this) + * + */ + +static void +pr_rewind(struct irs_pr *this) { + struct pvt *pvt = (struct pvt *)this->private; + char text[256]; + int code; + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return; + } + + if (irs_irp_send_command(pvt->girpdata, "setprotoent") != 0) { + return; + } + + code = irs_irp_read_response(pvt->girpdata, text, sizeof text); + if (code != IRPD_GETPROTO_SETOK) { + if (irp_log_errors) { + syslog(LOG_WARNING, "setprotoent failed: %s", text); + } + } + + return; +} + +/*% + * Prepares the cache if necessary and returns the next item in it. + * + */ + +static struct protoent * +pr_next(struct irs_pr *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct protoent *pr = &pvt->proto; + char *body; + size_t bodylen; + int code; + char text[256]; + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return (NULL); + } + + if (irs_irp_send_command(pvt->girpdata, "getprotoent") != 0) { + return (NULL); + } + + if (irs_irp_get_full_response(pvt->girpdata, &code, + text, sizeof text, + &body, &bodylen) != 0) { + return (NULL); + } + + if (code == IRPD_GETPROTO_OK) { + free_proto(pr); + if (irp_unmarshall_pr(pr, body) != 0) { + pr = NULL; + } + } else { + pr = NULL; + } + + if (body != NULL) { + memput(body, bodylen); + } + + return (pr); +} + +/*% + * void pr_minimize(struct irs_pr *this) + * + */ + +static void +pr_minimize(struct irs_pr *this) { + struct pvt *pvt = (struct pvt *)this->private; + + irs_irp_disconnect(pvt->girpdata); +} + +/*% + * Deallocate all the memory irp_unmarshall_pr allocated. + * + */ + +static void +free_proto(struct protoent *pr) { + char **p; + + if (pr == NULL) + return; + + if (pr->p_name != NULL) + free(pr->p_name); + + for (p = pr->p_aliases ; p != NULL && *p != NULL ; p++) + free(*p); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/irp_pw.c b/contrib/bind-9.5.2/lib/bind/irs/irp_pw.c new file mode 100644 index 0000000000..3722e5974d --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/irp_pw.c @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: irp_pw.c,v 1.4 2005/04/27 04:56:29 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* Extern */ + +#include "port_before.h" + +#ifndef WANT_IRS_PW +static int __bind_irs_pw_unneeded; +#else + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "irp_p.h" + + +/* Types */ + +struct pvt { + struct irp_p *girpdata; /*%< global IRP data */ + int warned; + struct passwd passwd; /*%< password structure */ +}; + +/* Forward */ + +static void pw_close(struct irs_pw *); +static struct passwd * pw_next(struct irs_pw *); +static struct passwd * pw_byname(struct irs_pw *, const char *); +static struct passwd * pw_byuid(struct irs_pw *, uid_t); +static void pw_rewind(struct irs_pw *); +static void pw_minimize(struct irs_pw *); + +static void free_passwd(struct passwd *pw); + +/* Public */ +struct irs_pw * +irs_irp_pw(struct irs_acc *this) { + struct irs_pw *pw; + struct pvt *pvt; + + if (!(pw = memget(sizeof *pw))) { + errno = ENOMEM; + return (NULL); + } + memset(pw, 0, sizeof *pw); + + if (!(pvt = memget(sizeof *pvt))) { + memput(pw, sizeof *pw); + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + pvt->girpdata = this->private; + + pw->private = pvt; + pw->close = pw_close; + pw->next = pw_next; + pw->byname = pw_byname; + pw->byuid = pw_byuid; + pw->rewind = pw_rewind; + pw->minimize = pw_minimize; + + return (pw); +} + +/* Methods */ + +/*% + * void pw_close(struct irs_pw *this) + * + */ + +static void +pw_close(struct irs_pw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + pw_minimize(this); + + free_passwd(&pvt->passwd); + + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +/*% + * struct passwd * pw_next(struct irs_pw *this) + * + */ + +static struct passwd * +pw_next(struct irs_pw *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct passwd *pw = &pvt->passwd; + char *body; + size_t bodylen; + int code; + char text[256]; + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return (NULL); + } + + if (irs_irp_send_command(pvt->girpdata, "getpwent") != 0) { + return (NULL); + } + + if (irs_irp_get_full_response(pvt->girpdata, &code, + text, sizeof text, + &body, &bodylen) != 0) { + return (NULL); + } + + if (code == IRPD_GETUSER_OK) { + free_passwd(pw); + if (irp_unmarshall_pw(pw, body) != 0) { + pw = NULL; + } + } else { + pw = NULL; + } + + if (body != NULL) { + memput(body, bodylen); + } + + return (pw); +} + +/*% + * struct passwd * pw_byname(struct irs_pw *this, const char *name) + * + */ + +static struct passwd * +pw_byname(struct irs_pw *this, const char *name) { + struct pvt *pvt = (struct pvt *)this->private; + struct passwd *pw = &pvt->passwd; + char *body = NULL; + char text[256]; + size_t bodylen; + int code; + + if (pw->pw_name != NULL && strcmp(name, pw->pw_name) == 0) { + return (pw); + } + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return (NULL); + } + + if (irs_irp_send_command(pvt->girpdata, "getpwnam %s", name) != 0) { + return (NULL); + } + + if (irs_irp_get_full_response(pvt->girpdata, &code, + text, sizeof text, + &body, &bodylen) != 0) { + return (NULL); + } + + if (code == IRPD_GETUSER_OK) { + free_passwd(pw); + if (irp_unmarshall_pw(pw, body) != 0) { + pw = NULL; + } + } else { + pw = NULL; + } + + if (body != NULL) { + memput(body, bodylen); + } + + return (pw); +} + +/*% + * struct passwd * pw_byuid(struct irs_pw *this, uid_t uid) + * + */ + +static struct passwd * +pw_byuid(struct irs_pw *this, uid_t uid) { + struct pvt *pvt = (struct pvt *)this->private; + char *body; + char text[256]; + size_t bodylen; + int code; + struct passwd *pw = &pvt->passwd; + + if (pw->pw_name != NULL && pw->pw_uid == uid) { + return (pw); + } + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return (NULL); + } + + if (irs_irp_send_command(pvt->girpdata, "getpwuid %d", uid) != 0) { + return (NULL); + } + + if (irs_irp_get_full_response(pvt->girpdata, &code, + text, sizeof text, + &body, &bodylen) != 0) { + return (NULL); + } + + if (code == IRPD_GETUSER_OK) { + free_passwd(pw); + if (irp_unmarshall_pw(pw, body) != 0) { + pw = NULL; + } + } else { + pw = NULL; + } + + if (body != NULL) { + memput(body, bodylen); + } + + return (pw); +} + +/*% + * void pw_rewind(struct irs_pw *this) + * + */ + +static void +pw_rewind(struct irs_pw *this) { + struct pvt *pvt = (struct pvt *)this->private; + char text[256]; + int code; + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return; + } + + if (irs_irp_send_command(pvt->girpdata, "setpwent") != 0) { + return; + } + + code = irs_irp_read_response(pvt->girpdata, text, sizeof text); + if (code != IRPD_GETUSER_SETOK) { + if (irp_log_errors) { + syslog(LOG_WARNING, "setpwent failed: %s", text); + } + } + + return; +} + +/*% + * void pw_minimize(struct irs_pw *this) + * + */ + +static void +pw_minimize(struct irs_pw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + irs_irp_disconnect(pvt->girpdata); +} + + +/* Private. */ + +/*% + * Deallocate all the memory irp_unmarshall_pw allocated. + * + */ + +static void +free_passwd(struct passwd *pw) { + if (pw == NULL) + return; + + if (pw->pw_name != NULL) + free(pw->pw_name); + + if (pw->pw_passwd != NULL) + free(pw->pw_passwd); + +#ifdef HAVE_PW_CLASS + if (pw->pw_class != NULL) + free(pw->pw_class); +#endif + + if (pw->pw_gecos != NULL) + free(pw->pw_gecos); + + if (pw->pw_dir != NULL) + free(pw->pw_dir); + + if (pw->pw_shell != NULL) + free(pw->pw_shell); +} + +#endif /* WANT_IRS_PW */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/irp_sv.c b/contrib/bind-9.5.2/lib/bind/irs/irp_sv.c new file mode 100644 index 0000000000..577e697fe6 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/irp_sv.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996,1998 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: irp_sv.c,v 1.3 2005/04/27 04:56:29 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* extern */ + +#include "port_before.h" + +#include +#include +#include + +#ifdef IRS_LCL_SV_DB +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "irs_p.h" +#include "lcl_p.h" +#include "irp_p.h" + +#include "port_after.h" + +/* Types */ + +struct pvt { + struct irp_p *girpdata; + int warned; + struct servent service; +}; + +/* Forward */ + +static void sv_close(struct irs_sv*); +static struct servent * sv_next(struct irs_sv *); +static struct servent * sv_byname(struct irs_sv *, const char *, + const char *); +static struct servent * sv_byport(struct irs_sv *, int, const char *); +static void sv_rewind(struct irs_sv *); +static void sv_minimize(struct irs_sv *); + +static void free_service(struct servent *sv); + + + +/* Public */ + +/*% + * struct irs_sv * irs_irp_sv(struct irs_acc *this) + * + */ + +struct irs_sv * +irs_irp_sv(struct irs_acc *this) { + struct irs_sv *sv; + struct pvt *pvt; + + if ((sv = memget(sizeof *sv)) == NULL) { + errno = ENOMEM; + return (NULL); + } + memset(sv, 0x0, sizeof *sv); + + if ((pvt = memget(sizeof *pvt)) == NULL) { + memput(sv, sizeof *sv); + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + pvt->girpdata = this->private; + + sv->private = pvt; + sv->close = sv_close; + sv->next = sv_next; + sv->byname = sv_byname; + sv->byport = sv_byport; + sv->rewind = sv_rewind; + sv->minimize = sv_minimize; + + return (sv); +} + +/* Methods */ + +/*% + * void sv_close(struct irs_sv *this) + * + */ + +static void +sv_close(struct irs_sv *this) { + struct pvt *pvt = (struct pvt *)this->private; + + sv_minimize(this); + + free_service(&pvt->service); + + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +/*% + * Fills the cache if necessary and returns the next item from it. + * + */ + +static struct servent * +sv_next(struct irs_sv *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct servent *sv = &pvt->service; + char *body; + size_t bodylen; + int code; + char text[256]; + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return (NULL); + } + + if (irs_irp_send_command(pvt->girpdata, "getservent") != 0) { + return (NULL); + } + + if (irs_irp_get_full_response(pvt->girpdata, &code, + text, sizeof text, + &body, &bodylen) != 0) { + return (NULL); + } + + if (code == IRPD_GETSERVICE_OK) { + free_service(sv); + if (irp_unmarshall_sv(sv, body) != 0) { + sv = NULL; + } + } else { + sv = NULL; + } + + if (body != NULL) { + memput(body, bodylen); + } + + return (sv); +} + +/*% + * struct servent * sv_byname(struct irs_sv *this, const char *name, + * const char *proto) + * + */ + +static struct servent * +sv_byname(struct irs_sv *this, const char *name, const char *proto) { + struct pvt *pvt = (struct pvt *)this->private; + struct servent *sv = &pvt->service; + char *body; + char text[256]; + size_t bodylen; + int code; + + if (sv->s_name != NULL && + strcmp(name, sv->s_name) == 0 && + strcasecmp(proto, sv->s_proto) == 0) { + return (sv); + } + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return (NULL); + } + + if (irs_irp_send_command(pvt->girpdata, "getservbyname %s %s", + name, proto) != 0) + return (NULL); + + if (irs_irp_get_full_response(pvt->girpdata, &code, + text, sizeof text, + &body, &bodylen) != 0) { + return (NULL); + } + + if (code == IRPD_GETSERVICE_OK) { + free_service(sv); + if (irp_unmarshall_sv(sv, body) != 0) { + sv = NULL; + } + } else { + sv = NULL; + } + + if (body != NULL) { + memput(body, bodylen); + } + + return (sv); +} + +/*% + * struct servent * sv_byport(struct irs_sv *this, int port, + * const char *proto) + * + */ + +static struct servent * +sv_byport(struct irs_sv *this, int port, const char *proto) { + struct pvt *pvt = (struct pvt *)this->private; + struct servent *sv = &pvt->service; + char *body; + size_t bodylen; + char text[256]; + int code; + + if (sv->s_name != NULL && + port == sv->s_port && + strcasecmp(proto, sv->s_proto) == 0) { + return (sv); + } + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return (NULL); + } + + if (irs_irp_send_command(pvt->girpdata, "getservbyport %d %s", + ntohs((short)port), proto) != 0) { + return (NULL); + } + + if (irs_irp_get_full_response(pvt->girpdata, &code, + text, sizeof text, + &body, &bodylen) != 0) { + return (NULL); + } + + if (code == IRPD_GETSERVICE_OK) { + free_service(sv); + if (irp_unmarshall_sv(sv, body) != 0) { + sv = NULL; + } + } else { + sv = NULL; + } + + if (body != NULL) { + memput(body, bodylen); + } + + return (sv); +} + +/*% + * void sv_rewind(struct irs_sv *this) + * + */ + +static void +sv_rewind(struct irs_sv *this) { + struct pvt *pvt = (struct pvt *)this->private; + char text[256]; + int code; + + if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) { + return; + } + + if (irs_irp_send_command(pvt->girpdata, "setservent") != 0) { + return; + } + + code = irs_irp_read_response(pvt->girpdata, text, sizeof text); + if (code != IRPD_GETSERVICE_SETOK) { + if (irp_log_errors) { + syslog(LOG_WARNING, "setservent failed: %s", text); + } + } + + return; +} + +/*% + * void sv_minimize(struct irs_sv *this) + * + */ + +static void +sv_minimize(struct irs_sv *this) { + struct pvt *pvt = (struct pvt *)this->private; + + irs_irp_disconnect(pvt->girpdata); +} + + + + + + +static void +free_service(struct servent *sv) { + char **p; + + if (sv == NULL) { + return; + } + + if (sv->s_name != NULL) { + free(sv->s_name); + } + + for (p = sv->s_aliases ; p != NULL && *p != NULL ; p++) { + free(*p); + } + + if (sv->s_proto != NULL) { + free(sv->s_proto); + } +} + + + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/irpmarshall.c b/contrib/bind-9.5.2/lib/bind/irs/irpmarshall.c new file mode 100644 index 0000000000..85ffff1866 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/irpmarshall.c @@ -0,0 +1,2301 @@ +/* + * Copyright(c) 1989, 1993, 1995 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: irpmarshall.c,v 1.7 2006/03/09 23:57:56 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#if 0 + +Check values are in approrpriate endian order. + +Double check memory allocations on unmarhsalling + +#endif + + +/* Extern */ + +#include "port_before.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "port_after.h" + + +#ifndef HAVE_STRNDUP +static char *strndup(const char *str, size_t len); +#endif + +static char **splitarray(const char *buffer, const char *buffend, char delim); +static int joinarray(char * const * argv, char *buffer, char delim); +static char *getfield(char **res, size_t reslen, char **buffer, char delim); +static size_t joinlength(char * const *argv); +static void free_array(char **argv, size_t entries); + +#define ADDR_T_STR(x) (x == AF_INET ? "AF_INET" :\ + (x == AF_INET6 ? "AF_INET6" : "UNKNOWN")) + +#define MAXPADDRSIZE (sizeof "255.255.255.255" + 1) + +static char COMMA = ','; + +static const char *COMMASTR = ","; +static const char *COLONSTR = ":"; + + + +/* See big comment at bottom of irpmarshall.h for description. */ + + +#ifdef WANT_IRS_PW +/* +++++++++++++++++++++++++ struct passwd +++++++++++++++++++++++++ */ + +/*% + * int irp_marshall_pw(const struct passwd *pw, char **buffer, size_t *len) + * + * notes: \li + * + * See irpmarshall.h + * + * return: \li + * + * 0 on sucess, -1 on failure. + * + */ + +int +irp_marshall_pw(const struct passwd *pw, char **buffer, size_t *len) { + size_t need = 1 ; /*%< for null byte */ + char pwUid[24]; + char pwGid[24]; + char pwChange[24]; + char pwExpire[24]; + const char *pwClass; + const char *fieldsep = COLONSTR; + + if (pw == NULL || len == NULL) { + errno = EINVAL; + return (-1); + } + + sprintf(pwUid, "%ld", (long)pw->pw_uid); + sprintf(pwGid, "%ld", (long)pw->pw_gid); + +#ifdef HAVE_PW_CHANGE + sprintf(pwChange, "%ld", (long)pw->pw_change); +#else + pwChange[0] = '0'; + pwChange[1] = '\0'; +#endif + +#ifdef HAVE_PW_EXPIRE + sprintf(pwExpire, "%ld", (long)pw->pw_expire); +#else + pwExpire[0] = '0'; + pwExpire[1] = '\0'; +#endif + +#ifdef HAVE_PW_CLASS + pwClass = pw->pw_class; +#else + pwClass = ""; +#endif + + need += strlen(pw->pw_name) + 1; /*%< one for fieldsep */ + need += strlen(pw->pw_passwd) + 1; + need += strlen(pwUid) + 1; + need += strlen(pwGid) + 1; + need += strlen(pwClass) + 1; + need += strlen(pwChange) + 1; + need += strlen(pwExpire) + 1; + need += strlen(pw->pw_gecos) + 1; + need += strlen(pw->pw_dir) + 1; + need += strlen(pw->pw_shell) + 1; + + if (buffer == NULL) { + *len = need; + return (0); + } + + if (*buffer != NULL && need > *len) { + errno = EINVAL; + return (-1); + } + + if (*buffer == NULL) { + need += 2; /*%< for CRLF */ + *buffer = memget(need); + if (*buffer == NULL) { + errno = ENOMEM; + return (-1); + } + + *len = need; + } + + strcpy(*buffer, pw->pw_name); strcat(*buffer, fieldsep); + strcat(*buffer, pw->pw_passwd); strcat(*buffer, fieldsep); + strcat(*buffer, pwUid); strcat(*buffer, fieldsep); + strcat(*buffer, pwGid); strcat(*buffer, fieldsep); + strcat(*buffer, pwClass); strcat(*buffer, fieldsep); + strcat(*buffer, pwChange); strcat(*buffer, fieldsep); + strcat(*buffer, pwExpire); strcat(*buffer, fieldsep); + strcat(*buffer, pw->pw_gecos); strcat(*buffer, fieldsep); + strcat(*buffer, pw->pw_dir); strcat(*buffer, fieldsep); + strcat(*buffer, pw->pw_shell); strcat(*buffer, fieldsep); + + return (0); +} + +/*% + * int irp_unmarshall_pw(struct passwd *pw, char *buffer) + * + * notes: \li + * + * See irpmarshall.h + * + * return: \li + * + * 0 on success, -1 on failure + * + */ + +int +irp_unmarshall_pw(struct passwd *pw, char *buffer) { + char *name, *pass, *class, *gecos, *dir, *shell; + uid_t pwuid; + gid_t pwgid; + time_t pwchange; + time_t pwexpire; + char *p; + long t; + char tmpbuf[24]; + char *tb = &tmpbuf[0]; + char fieldsep = ':'; + int myerrno = EINVAL; + + name = pass = class = gecos = dir = shell = NULL; + p = buffer; + + /* pw_name field */ + name = NULL; + if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0) { + goto error; + } + + /* pw_passwd field */ + pass = NULL; + if (getfield(&pass, 0, &p, fieldsep) == NULL) { /*%< field can be empty */ + goto error; + } + + + /* pw_uid field */ + tb = tmpbuf; + if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL || + strlen(tb) == 0) { + goto error; + } + t = strtol(tmpbuf, &tb, 10); + if (*tb) { + goto error; /*%< junk in value */ + } + pwuid = (uid_t)t; + if ((long) pwuid != t) { /*%< value must have been too big. */ + goto error; + } + + + + /* pw_gid field */ + tb = tmpbuf; + if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL || + strlen(tb) == 0) { + goto error; + } + t = strtol(tmpbuf, &tb, 10); + if (*tb) { + goto error; /*%< junk in value */ + } + pwgid = (gid_t)t; + if ((long)pwgid != t) { /*%< value must have been too big. */ + goto error; + } + + + + /* pw_class field */ + class = NULL; + if (getfield(&class, 0, &p, fieldsep) == NULL) { + goto error; + } + + + + /* pw_change field */ + tb = tmpbuf; + if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL || + strlen(tb) == 0) { + goto error; + } + t = strtol(tmpbuf, &tb, 10); + if (*tb) { + goto error; /*%< junk in value */ + } + pwchange = (time_t)t; + if ((long)pwchange != t) { /*%< value must have been too big. */ + goto error; + } + + + + /* pw_expire field */ + tb = tmpbuf; + if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL || + strlen(tb) == 0) { + goto error; + } + t = strtol(tmpbuf, &tb, 10); + if (*tb) { + goto error; /*%< junk in value */ + } + pwexpire = (time_t)t; + if ((long) pwexpire != t) { /*%< value must have been too big. */ + goto error; + } + + + + /* pw_gecos field */ + gecos = NULL; + if (getfield(&gecos, 0, &p, fieldsep) == NULL) { + goto error; + } + + + + /* pw_dir field */ + dir = NULL; + if (getfield(&dir, 0, &p, fieldsep) == NULL) { + goto error; + } + + + + /* pw_shell field */ + shell = NULL; + if (getfield(&shell, 0, &p, fieldsep) == NULL) { + goto error; + } + + + + pw->pw_name = name; + pw->pw_passwd = pass; + pw->pw_uid = pwuid; + pw->pw_gid = pwgid; + pw->pw_gecos = gecos; + pw->pw_dir = dir; + pw->pw_shell = shell; + +#ifdef HAVE_PW_CHANGE + pw->pw_change = pwchange; +#endif +#ifdef HAVE_PW_CLASS + pw->pw_class = class; +#endif +#ifdef HAVE_PW_EXPIRE + pw->pw_expire = pwexpire; +#endif + + return (0); + + error: + errno = myerrno; + + if (name != NULL) free(name); + if (pass != NULL) free(pass); + if (gecos != NULL) free(gecos); + if (dir != NULL) free(dir); + if (shell != NULL) free(shell); + + return (-1); +} + +/* ------------------------- struct passwd ------------------------- */ +#endif /* WANT_IRS_PW */ +/* +++++++++++++++++++++++++ struct group +++++++++++++++++++++++++ */ + +/*% + * int irp_marshall_gr(const struct group *gr, char **buffer, size_t *len) + * + * notes: \li + * + * See irpmarshall.h. + * + * return: \li + * + * 0 on success, -1 on failure + */ + +int +irp_marshall_gr(const struct group *gr, char **buffer, size_t *len) { + size_t need = 1; /*%< for null byte */ + char grGid[24]; + const char *fieldsep = COLONSTR; + + if (gr == NULL || len == NULL) { + errno = EINVAL; + return (-1); + } + + sprintf(grGid, "%ld", (long)gr->gr_gid); + + need += strlen(gr->gr_name) + 1; +#ifndef MISSING_GR_PASSWD + need += strlen(gr->gr_passwd) + 1; +#else + need++; +#endif + need += strlen(grGid) + 1; + need += joinlength(gr->gr_mem) + 1; + + if (buffer == NULL) { + *len = need; + return (0); + } + + if (*buffer != NULL && need > *len) { + errno = EINVAL; + return (-1); + } + + if (*buffer == NULL) { + need += 2; /*%< for CRLF */ + *buffer = memget(need); + if (*buffer == NULL) { + errno = ENOMEM; + return (-1); + } + + *len = need; + } + + strcpy(*buffer, gr->gr_name); strcat(*buffer, fieldsep); +#ifndef MISSING_GR_PASSWD + strcat(*buffer, gr->gr_passwd); +#endif + strcat(*buffer, fieldsep); + strcat(*buffer, grGid); strcat(*buffer, fieldsep); + joinarray(gr->gr_mem, *buffer, COMMA) ; strcat(*buffer, fieldsep); + + return (0); +} + +/*% + * int irp_unmarshall_gr(struct group *gr, char *buffer) + * + * notes: \li + * + * See irpmarshall.h + * + * return: \li + * + * 0 on success and -1 on failure. + * + */ + +int +irp_unmarshall_gr(struct group *gr, char *buffer) { + char *p, *q; + gid_t grgid; + long t; + char *name = NULL; + char *pass = NULL; + char **members = NULL; + char tmpbuf[24]; + char *tb; + char fieldsep = ':'; + int myerrno = EINVAL; + + if (gr == NULL || buffer == NULL) { + errno = EINVAL; + return (-1); + } + + p = buffer; + + /* gr_name field */ + name = NULL; + if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) { + goto error; + } + + + /* gr_passwd field */ + pass = NULL; + if (getfield(&pass, 0, &p, fieldsep) == NULL) { + goto error; + } + + + /* gr_gid field */ + tb = tmpbuf; + if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL || + strlen(tb) == 0U) { + goto error; + } + t = strtol(tmpbuf, &tb, 10); + if (*tb) { + goto error; /*%< junk in value */ + } + grgid = (gid_t)t; + if ((long) grgid != t) { /*%< value must have been too big. */ + goto error; + } + + + /* gr_mem field. Member names are separated by commas */ + q = strchr(p, fieldsep); + if (q == NULL) { + goto error; + } + members = splitarray(p, q, COMMA); + if (members == NULL) { + myerrno = errno; + goto error; + } + p = q + 1; + + + gr->gr_name = name; +#ifndef MISSING_GR_PASSWD + gr->gr_passwd = pass; +#endif + gr->gr_gid = grgid; + gr->gr_mem = members; + + return (0); + + error: + errno = myerrno; + + if (name != NULL) free(name); + if (pass != NULL) free(pass); + + return (-1); +} + + +/* ------------------------- struct group ------------------------- */ + + + + +/* +++++++++++++++++++++++++ struct servent +++++++++++++++++++++++++ */ + +/*% + * int irp_marshall_sv(const struct servent *sv, char **buffer, size_t *len) + * + * notes: \li + * + * See irpmarshall.h + * + * return: \li + * + * 0 on success, -1 on failure. + * + */ + +int +irp_marshall_sv(const struct servent *sv, char **buffer, size_t *len) { + size_t need = 1; /*%< for null byte */ + char svPort[24]; + const char *fieldsep = COLONSTR; + short realport; + + if (sv == NULL || len == NULL) { + errno = EINVAL; + return (-1); + } + + /* the int s_port field is actually a short in network order. We + want host order to make the marshalled data look correct */ + realport = ntohs((short)sv->s_port); + sprintf(svPort, "%d", realport); + + need += strlen(sv->s_name) + 1; + need += joinlength(sv->s_aliases) + 1; + need += strlen(svPort) + 1; + need += strlen(sv->s_proto) + 1; + + if (buffer == NULL) { + *len = need; + return (0); + } + + if (*buffer != NULL && need > *len) { + errno = EINVAL; + return (-1); + } + + if (*buffer == NULL) { + need += 2; /*%< for CRLF */ + *buffer = memget(need); + if (*buffer == NULL) { + errno = ENOMEM; + return (-1); + } + + *len = need; + } + + strcpy(*buffer, sv->s_name); strcat(*buffer, fieldsep); + joinarray(sv->s_aliases, *buffer, COMMA); strcat(*buffer, fieldsep); + strcat(*buffer, svPort); strcat(*buffer, fieldsep); + strcat(*buffer, sv->s_proto); strcat(*buffer, fieldsep); + + return (0); +} + +/*% + * int irp_unmarshall_sv(struct servent *sv, char *buffer) + * + * notes: \li + * + * See irpmarshall.h + * + * return: \li + * + * 0 on success, -1 on failure. + * + */ + +int +irp_unmarshall_sv(struct servent *sv, char *buffer) { + char *p, *q; + short svport; + long t; + char *name = NULL; + char *proto = NULL; + char **aliases = NULL; + char tmpbuf[24]; + char *tb; + char fieldsep = ':'; + int myerrno = EINVAL; + + if (sv == NULL || buffer == NULL) + return (-1); + + p = buffer; + + + /* s_name field */ + name = NULL; + if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) { + goto error; + } + + + /* s_aliases field */ + q = strchr(p, fieldsep); + if (q == NULL) { + goto error; + } + aliases = splitarray(p, q, COMMA); + if (aliases == NULL) { + myerrno = errno; + goto error; + } + p = q + 1; + + + /* s_port field */ + tb = tmpbuf; + if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL || + strlen(tb) == 0U) { + goto error; + } + t = strtol(tmpbuf, &tb, 10); + if (*tb) { + goto error; /*%< junk in value */ + } + svport = (short)t; + if ((long) svport != t) { /*%< value must have been too big. */ + goto error; + } + svport = htons(svport); + + /* s_proto field */ + proto = NULL; + if (getfield(&proto, 0, &p, fieldsep) == NULL) { + goto error; + } + + sv->s_name = name; + sv->s_aliases = aliases; + sv->s_port = svport; + sv->s_proto = proto; + + return (0); + + error: + errno = myerrno; + + if (name != NULL) free(name); + if (proto != NULL) free(proto); + free_array(aliases, 0); + + return (-1); +} + + +/* ------------------------- struct servent ------------------------- */ + +/* +++++++++++++++++++++++++ struct protoent +++++++++++++++++++++++++ */ + +/*% + * int irp_marshall_pr(struct protoent *pr, char **buffer, size_t *len) + * + * notes: \li + * + * See irpmarshall.h + * + * return: \li + * + * 0 on success and -1 on failure. + * + */ + +int +irp_marshall_pr(struct protoent *pr, char **buffer, size_t *len) { + size_t need = 1; /*%< for null byte */ + char prProto[24]; + const char *fieldsep = COLONSTR; + + if (pr == NULL || len == NULL) { + errno = EINVAL; + return (-1); + } + + sprintf(prProto, "%d", (int)pr->p_proto); + + need += strlen(pr->p_name) + 1; + need += joinlength(pr->p_aliases) + 1; + need += strlen(prProto) + 1; + + if (buffer == NULL) { + *len = need; + return (0); + } + + if (*buffer != NULL && need > *len) { + errno = EINVAL; + return (-1); + } + + if (*buffer == NULL) { + need += 2; /*%< for CRLF */ + *buffer = memget(need); + if (*buffer == NULL) { + errno = ENOMEM; + return (-1); + } + + *len = need; + } + + strcpy(*buffer, pr->p_name); strcat(*buffer, fieldsep); + joinarray(pr->p_aliases, *buffer, COMMA); strcat(*buffer, fieldsep); + strcat(*buffer, prProto); strcat(*buffer, fieldsep); + + return (0); + +} + +/*% + * int irp_unmarshall_pr(struct protoent *pr, char *buffer) + * + * notes: \li + * + * See irpmarshall.h + * + * return: \li + * + * 0 on success, -1 on failure + * + */ + +int irp_unmarshall_pr(struct protoent *pr, char *buffer) { + char *p, *q; + int prproto; + long t; + char *name = NULL; + char **aliases = NULL; + char tmpbuf[24]; + char *tb; + char fieldsep = ':'; + int myerrno = EINVAL; + + if (pr == NULL || buffer == NULL) { + errno = EINVAL; + return (-1); + } + + p = buffer; + + /* p_name field */ + name = NULL; + if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) { + goto error; + } + + + /* p_aliases field */ + q = strchr(p, fieldsep); + if (q == NULL) { + goto error; + } + aliases = splitarray(p, q, COMMA); + if (aliases == NULL) { + myerrno = errno; + goto error; + } + p = q + 1; + + + /* p_proto field */ + tb = tmpbuf; + if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL || + strlen(tb) == 0U) { + goto error; + } + t = strtol(tmpbuf, &tb, 10); + if (*tb) { + goto error; /*%< junk in value */ + } + prproto = (int)t; + if ((long) prproto != t) { /*%< value must have been too big. */ + goto error; + } + + pr->p_name = name; + pr->p_aliases = aliases; + pr->p_proto = prproto; + + return (0); + + error: + errno = myerrno; + + if (name != NULL) free(name); + free_array(aliases, 0); + + return (-1); +} + +/* ------------------------- struct protoent ------------------------- */ + + + +/* +++++++++++++++++++++++++ struct hostent +++++++++++++++++++++++++ */ + +/*% + * int irp_marshall_ho(struct hostent *ho, char **buffer, size_t *len) + * + * notes: \li + * + * See irpmarshall.h. + * + * return: \li + * + * 0 on success, -1 on failure. + * + */ + +int +irp_marshall_ho(struct hostent *ho, char **buffer, size_t *len) { + size_t need = 1; /*%< for null byte */ + char hoaddrtype[24]; + char holength[24]; + char **av; + char *p; + int addrlen; + int malloced = 0; + size_t remlen; + const char *fieldsep = "@"; + + if (ho == NULL || len == NULL) { + errno = EINVAL; + return (-1); + } + + switch(ho->h_addrtype) { + case AF_INET: + strcpy(hoaddrtype, "AF_INET"); + break; + + case AF_INET6: + strcpy(hoaddrtype, "AF_INET6"); + break; + + default: + errno = EINVAL; + return (-1); + } + + sprintf(holength, "%d", ho->h_length); + + need += strlen(ho->h_name) + 1; + need += joinlength(ho->h_aliases) + 1; + need += strlen(hoaddrtype) + 1; + need += strlen(holength) + 1; + + /* we determine an upper bound on the string length needed, not an + exact length. */ + addrlen = (ho->h_addrtype == AF_INET ? 16 : 46) ; /*%< XX other AF's?? */ + for (av = ho->h_addr_list; av != NULL && *av != NULL ; av++) + need += addrlen; + + if (buffer == NULL) { + *len = need; + return (0); + } + + if (*buffer != NULL && need > *len) { + errno = EINVAL; + return (-1); + } + + if (*buffer == NULL) { + need += 2; /*%< for CRLF */ + *buffer = memget(need); + if (*buffer == NULL) { + errno = ENOMEM; + return (-1); + } + + *len = need; + malloced = 1; + } + + strcpy(*buffer, ho->h_name); strcat(*buffer, fieldsep); + joinarray(ho->h_aliases, *buffer, COMMA); strcat(*buffer, fieldsep); + strcat(*buffer, hoaddrtype); strcat(*buffer, fieldsep); + strcat(*buffer, holength); strcat(*buffer, fieldsep); + + p = *buffer + strlen(*buffer); + remlen = need - strlen(*buffer); + for (av = ho->h_addr_list ; av != NULL && *av != NULL ; av++) { + if (inet_ntop(ho->h_addrtype, *av, p, remlen) == NULL) { + goto error; + } + if (*(av + 1) != NULL) + strcat(p, COMMASTR); + remlen -= strlen(p); + p += strlen(p); + } + strcat(*buffer, fieldsep); + + return (0); + + error: + if (malloced) { + memput(*buffer, need); + } + + return (-1); +} + +/*% + * int irp_unmarshall_ho(struct hostent *ho, char *buffer) + * + * notes: \li + * + * See irpmarshall.h. + * + * return: \li + * + * 0 on success, -1 on failure. + * + */ + +int +irp_unmarshall_ho(struct hostent *ho, char *buffer) { + char *p, *q, *r; + int hoaddrtype; + int holength; + long t; + char *name; + char **aliases = NULL; + char **hohaddrlist = NULL; + size_t hoaddrsize; + char tmpbuf[24]; + char *tb; + char **alist; + int addrcount; + char fieldsep = '@'; + int myerrno = EINVAL; + + if (ho == NULL || buffer == NULL) { + errno = EINVAL; + return (-1); + } + + p = buffer; + + /* h_name field */ + name = NULL; + if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) { + goto error; + } + + + /* h_aliases field */ + q = strchr(p, fieldsep); + if (q == NULL) { + goto error; + } + aliases = splitarray(p, q, COMMA); + if (aliases == NULL) { + myerrno = errno; + goto error; + } + p = q + 1; + + + /* h_addrtype field */ + tb = tmpbuf; + if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL || + strlen(tb) == 0U) { + goto error; + } + if (strcmp(tmpbuf, "AF_INET") == 0) + hoaddrtype = AF_INET; + else if (strcmp(tmpbuf, "AF_INET6") == 0) + hoaddrtype = AF_INET6; + else + goto error; + + + /* h_length field */ + tb = tmpbuf; + if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL || + strlen(tb) == 0U) { + goto error; + } + t = strtol(tmpbuf, &tb, 10); + if (*tb) { + goto error; /*%< junk in value */ + } + holength = (int)t; + if ((long) holength != t) { /*%< value must have been too big. */ + goto error; + } + + + /* h_addr_list field */ + q = strchr(p, fieldsep); + if (q == NULL) + goto error; + + /* count how many addresss are in there */ + if (q > p + 1) { + for (addrcount = 1, r = p ; r != q ; r++) { + if (*r == COMMA) + addrcount++; + } + } else { + addrcount = 0; + } + + hoaddrsize = (addrcount + 1) * sizeof (char *); + hohaddrlist = malloc(hoaddrsize); + if (hohaddrlist == NULL) { + myerrno = ENOMEM; + goto error; + } + + memset(hohaddrlist, 0x0, hoaddrsize); + + alist = hohaddrlist; + for (t = 0, r = p ; r != q ; p = r + 1, t++) { + char saved; + while (r != q && *r != COMMA) r++; + saved = *r; + *r = 0x0; + + alist[t] = malloc(hoaddrtype == AF_INET ? 4 : 16); + if (alist[t] == NULL) { + myerrno = ENOMEM; + goto error; + } + + if (inet_pton(hoaddrtype, p, alist[t]) == -1) + goto error; + *r = saved; + } + alist[t] = NULL; + + ho->h_name = name; + ho->h_aliases = aliases; + ho->h_addrtype = hoaddrtype; + ho->h_length = holength; + ho->h_addr_list = hohaddrlist; + + return (0); + + error: + errno = myerrno; + + if (name != NULL) free(name); + free_array(hohaddrlist, 0); + free_array(aliases, 0); + + return (-1); +} + +/* ------------------------- struct hostent------------------------- */ + + + +/* +++++++++++++++++++++++++ struct netgrp +++++++++++++++++++++++++ */ + +/*% + * int irp_marshall_ng(const char *host, const char *user, + * const char *domain, char *buffer, size_t *len) + * + * notes: \li + * + * See note for irp_marshall_ng_start + * + * return: \li + * + * 0 on success, 0 on failure. + * + */ + +int +irp_marshall_ng(const char *host, const char *user, const char *domain, + char **buffer, size_t *len) { + size_t need = 1; /*%< for nul byte */ + const char *fieldsep = ","; + + if (len == NULL) { + errno = EINVAL; + return (-1); + } + + need += 4; /*%< two parens and two commas */ + need += (host == NULL ? 0 : strlen(host)); + need += (user == NULL ? 0 : strlen(user)); + need += (domain == NULL ? 0 : strlen(domain)); + + if (buffer == NULL) { + *len = need; + return (0); + } else if (*buffer != NULL && need > *len) { + errno = EINVAL; + return (-1); + } + + if (*buffer == NULL) { + need += 2; /*%< for CRLF */ + *buffer = memget(need); + if (*buffer == NULL) { + errno = ENOMEM; + return (-1); + } + + *len = need; + } + + (*buffer)[0] = '('; + (*buffer)[1] = '\0'; + + if (host != NULL) + strcat(*buffer, host); + strcat(*buffer, fieldsep); + + if (user != NULL) + strcat(*buffer, user); + strcat(*buffer, fieldsep); + + if (domain != NULL) + strcat(*buffer, domain); + strcat(*buffer, ")"); + + return (0); +} + + + +/* ---------- */ + +/*% + * int irp_unmarshall_ng(const char **host, const char **user, + * const char **domain, char *buffer) + * + * notes: \li + * + * Unpacks the BUFFER into 3 character arrays it allocates and assigns + * to *HOST, *USER and *DOMAIN. If any field of the value is empty, + * then the corresponding paramater value will be set to NULL. + * + * return: \li + * + * 0 on success and -1 on failure. + */ + +int +irp_unmarshall_ng(const char **hostp, const char **userp, const char **domainp, + char *buffer) +{ + char *p, *q; + char fieldsep = ','; + int myerrno = EINVAL; + char *host, *user, *domain; + + if (userp == NULL || hostp == NULL || + domainp == NULL || buffer == NULL) { + errno = EINVAL; + return (-1); + } + + host = user = domain = NULL; + + p = buffer; + while (isspace((unsigned char)*p)) { + p++; + } + if (*p != '(') { + goto error; + } + + q = p + 1; + while (*q && *q != fieldsep) + q++; + if (!*q) { + goto error; + } else if (q > p + 1) { + host = strndup(p, q - p); + } + + p = q + 1; + if (!*p) { + goto error; + } else if (*p != fieldsep) { + q = p + 1; + while (*q && *q != fieldsep) + q++; + if (!*q) { + goto error; + } + user = strndup(p, q - p); + } else { + p++; + } + + if (!*p) { + goto error; + } else if (*p != ')') { + q = p + 1; + while (*q && *q != ')') + q++; + if (!*q) { + goto error; + } + domain = strndup(p, q - p); + } + *hostp = host; + *userp = user; + *domainp = domain; + + return (0); + + error: + errno = myerrno; + + if (host != NULL) free(host); + if (user != NULL) free(user); + + return (-1); +} + +/* ------------------------- struct netgrp ------------------------- */ + + + + +/* +++++++++++++++++++++++++ struct nwent +++++++++++++++++++++++++ */ + +/*% + * int irp_marshall_nw(struct nwent *ne, char **buffer, size_t *len) + * + * notes: \li + * + * See at top. + * + * return: \li + * + * 0 on success and -1 on failure. + * + */ + +int +irp_marshall_nw(struct nwent *ne, char **buffer, size_t *len) { + size_t need = 1; /*%< for null byte */ + char nAddrType[24]; + char nNet[MAXPADDRSIZE]; + const char *fieldsep = COLONSTR; + + if (ne == NULL || len == NULL) { + return (-1); + } + + strcpy(nAddrType, ADDR_T_STR(ne->n_addrtype)); + + if (inet_net_ntop(ne->n_addrtype, ne->n_addr, ne->n_length, + nNet, sizeof nNet) == NULL) { + return (-1); + } + + + need += strlen(ne->n_name) + 1; + need += joinlength(ne->n_aliases) + 1; + need += strlen(nAddrType) + 1; + need += strlen(nNet) + 1; + + if (buffer == NULL) { + *len = need; + return (0); + } + + if (*buffer != NULL && need > *len) { + errno = EINVAL; + return (-1); + } + + if (*buffer == NULL) { + need += 2; /*%< for CRLF */ + *buffer = memget(need); + if (*buffer == NULL) { + errno = ENOMEM; + return (-1); + } + + *len = need; + } + + strcpy(*buffer, ne->n_name); strcat(*buffer, fieldsep); + joinarray(ne->n_aliases, *buffer, COMMA) ; strcat(*buffer, fieldsep); + strcat(*buffer, nAddrType); strcat(*buffer, fieldsep); + strcat(*buffer, nNet); strcat(*buffer, fieldsep); + + return (0); +} + +/*% + * int irp_unmarshall_nw(struct nwent *ne, char *buffer) + * + * notes: \li + * + * See note up top. + * + * return: \li + * + * 0 on success and -1 on failure. + * + */ + +int +irp_unmarshall_nw(struct nwent *ne, char *buffer) { + char *p, *q; + int naddrtype; + long nnet; + int bits; + char *name = NULL; + char **aliases = NULL; + char tmpbuf[24]; + char *tb; + char fieldsep = ':'; + int myerrno = EINVAL; + + if (ne == NULL || buffer == NULL) { + goto error; + } + + p = buffer; + + /* n_name field */ + name = NULL; + if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) { + goto error; + } + + + /* n_aliases field. Aliases are separated by commas */ + q = strchr(p, fieldsep); + if (q == NULL) { + goto error; + } + aliases = splitarray(p, q, COMMA); + if (aliases == NULL) { + myerrno = errno; + goto error; + } + p = q + 1; + + + /* h_addrtype field */ + tb = tmpbuf; + if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL || + strlen(tb) == 0U) { + goto error; + } + if (strcmp(tmpbuf, "AF_INET") == 0) + naddrtype = AF_INET; + else if (strcmp(tmpbuf, "AF_INET6") == 0) + naddrtype = AF_INET6; + else + goto error; + + + /* n_net field */ + tb = tmpbuf; + if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL || + strlen(tb) == 0U) { + goto error; + } + nnet = 0; + bits = inet_net_pton(naddrtype, tmpbuf, &nnet, sizeof nnet); + if (bits < 0) { + goto error; + } + + /* nnet = ntohl(nnet); */ /* keep in network order for nwent */ + + ne->n_name = name; + ne->n_aliases = aliases; + ne->n_addrtype = naddrtype; + ne->n_length = bits; + ne->n_addr = malloc(sizeof nnet); + if (ne->n_addr == NULL) { + goto error; + } + + memcpy(ne->n_addr, &nnet, sizeof nnet); + + return (0); + + error: + errno = myerrno; + + if (name != NULL) free(name); + free_array(aliases, 0); + + return (-1); +} + + +/* ------------------------- struct nwent ------------------------- */ + + +/* +++++++++++++++++++++++++ struct netent +++++++++++++++++++++++++ */ + +/*% + * int irp_marshall_ne(struct netent *ne, char **buffer, size_t *len) + * + * notes: \li + * + * See at top. + * + * return: \li + * + * 0 on success and -1 on failure. + * + */ + +int +irp_marshall_ne(struct netent *ne, char **buffer, size_t *len) { + size_t need = 1; /*%< for null byte */ + char nAddrType[24]; + char nNet[MAXPADDRSIZE]; + const char *fieldsep = COLONSTR; + long nval; + + if (ne == NULL || len == NULL) { + return (-1); + } + + strcpy(nAddrType, ADDR_T_STR(ne->n_addrtype)); + + nval = htonl(ne->n_net); + if (inet_ntop(ne->n_addrtype, &nval, nNet, sizeof nNet) == NULL) { + return (-1); + } + + need += strlen(ne->n_name) + 1; + need += joinlength(ne->n_aliases) + 1; + need += strlen(nAddrType) + 1; + need += strlen(nNet) + 1; + + if (buffer == NULL) { + *len = need; + return (0); + } + + if (*buffer != NULL && need > *len) { + errno = EINVAL; + return (-1); + } + + if (*buffer == NULL) { + need += 2; /*%< for CRLF */ + *buffer = memget(need); + if (*buffer == NULL) { + errno = ENOMEM; + return (-1); + } + + *len = need; + } + + strcpy(*buffer, ne->n_name); strcat(*buffer, fieldsep); + joinarray(ne->n_aliases, *buffer, COMMA) ; strcat(*buffer, fieldsep); + strcat(*buffer, nAddrType); strcat(*buffer, fieldsep); + strcat(*buffer, nNet); strcat(*buffer, fieldsep); + + return (0); +} + +/*% + * int irp_unmarshall_ne(struct netent *ne, char *buffer) + * + * notes: \li + * + * See note up top. + * + * return: \li + * + * 0 on success and -1 on failure. + * + */ + +int +irp_unmarshall_ne(struct netent *ne, char *buffer) { + char *p, *q; + int naddrtype; + long nnet; + int bits; + char *name = NULL; + char **aliases = NULL; + char tmpbuf[24]; + char *tb; + char fieldsep = ':'; + int myerrno = EINVAL; + + if (ne == NULL || buffer == NULL) { + goto error; + } + + p = buffer; + + /* n_name field */ + name = NULL; + if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) { + goto error; + } + + + /* n_aliases field. Aliases are separated by commas */ + q = strchr(p, fieldsep); + if (q == NULL) { + goto error; + } + aliases = splitarray(p, q, COMMA); + if (aliases == NULL) { + myerrno = errno; + goto error; + } + p = q + 1; + + + /* h_addrtype field */ + tb = tmpbuf; + if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL || + strlen(tb) == 0U) { + goto error; + } + if (strcmp(tmpbuf, "AF_INET") == 0) + naddrtype = AF_INET; + else if (strcmp(tmpbuf, "AF_INET6") == 0) + naddrtype = AF_INET6; + else + goto error; + + + /* n_net field */ + tb = tmpbuf; + if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL || + strlen(tb) == 0U) { + goto error; + } + bits = inet_net_pton(naddrtype, tmpbuf, &nnet, sizeof nnet); + if (bits < 0) { + goto error; + } + nnet = ntohl(nnet); + + ne->n_name = name; + ne->n_aliases = aliases; + ne->n_addrtype = naddrtype; + ne->n_net = nnet; + + return (0); + + error: + errno = myerrno; + + if (name != NULL) free(name); + free_array(aliases, 0); + + return (-1); +} + + +/* ------------------------- struct netent ------------------------- */ + + +/* =========================================================================== */ + +/*% + * static char ** splitarray(const char *buffer, const char *buffend, char delim) + * + * notes: \li + * + * Split a delim separated astring. Not allowed + * to have two delims next to each other. BUFFER points to begining of + * string, BUFFEND points to one past the end of the string + * (i.e. points at where the null byte would be if null + * terminated). + * + * return: \li + * + * Returns a malloced array of pointers, each pointer pointing to a + * malloced string. If BUFEER is an empty string, then return values is + * array of 1 pointer that is NULL. Returns NULL on failure. + * + */ + +static char ** +splitarray(const char *buffer, const char *buffend, char delim) { + const char *p, *q; + int count = 0; + char **arr = NULL; + char **aptr; + + if (buffend < buffer) + return (NULL); + else if (buffend > buffer && *buffer == delim) + return (NULL); + else if (buffend > buffer && *(buffend - 1) == delim) + return (NULL); + + /* count the number of field and make sure none are empty */ + if (buffend > buffer + 1) { + for (count = 1, q = buffer ; q != buffend ; q++) { + if (*q == delim) { + if (q > buffer && (*(q - 1) == delim)) { + errno = EINVAL; + return (NULL); + } + count++; + } + } + } + + if (count > 0) { + count++ ; /*%< for NULL at end */ + aptr = arr = malloc(count * sizeof (char *)); + if (aptr == NULL) { + errno = ENOMEM; + return (NULL); + } + + memset(arr, 0x0, count * sizeof (char *)); + for (p = buffer ; p < buffend ; p++) { + for (q = p ; *q != delim && q != buffend ; q++) + /* nothing */; + *aptr = strndup(p, q - p); + + p = q; + aptr++; + } + *aptr = NULL; + } else { + arr = malloc(sizeof (char *)); + if (arr == NULL) { + errno = ENOMEM; + return (NULL); + } + + *arr = NULL; + } + + return (arr); +} + +/*% + * static size_t joinlength(char * const *argv) + * + * return: \li + * + * the number of bytes in all the arrays pointed at + * by argv, including their null bytes(which will usually be turned + * into commas). + * + * + */ + +static size_t +joinlength(char * const *argv) { + int len = 0; + + while (argv && *argv) { + len += (strlen(*argv) + 1); + argv++; + } + + return (len); +} + +/*% + * int joinarray(char * const *argv, char *buffer, char delim) + * + * notes: \li + * + * Copy all the ARGV strings into the end of BUFFER + * separating them with DELIM. BUFFER is assumed to have + * enough space to hold everything and to be already null-terminated. + * + * return: \li + * + * 0 unless argv or buffer is NULL. + * + * + */ + +static int +joinarray(char * const *argv, char *buffer, char delim) { + char * const *p; + char sep[2]; + + if (argv == NULL || buffer == NULL) { + errno = EINVAL; + return (-1); + } + + sep[0] = delim; + sep[1] = 0x0; + + for (p = argv ; *p != NULL ; p++) { + strcat(buffer, *p); + if (*(p + 1) != NULL) { + strcat(buffer, sep); + } + } + + return (0); +} + +/*% + * static char * getfield(char **res, size_t reslen, char **ptr, char delim) + * + * notes: \li + * + * Stores in *RES, which is a buffer of length RESLEN, a + * copy of the bytes from *PTR up to and including the first + * instance of DELIM. If *RES is NULL, then it will be + * assigned a malloced buffer to hold the copy. *PTR is + * modified to point at the found delimiter. + * + * return: \li + * + * If there was no delimiter, then NULL is returned, + * otherewise *RES is returned. + * + */ + +static char * +getfield(char **res, size_t reslen, char **ptr, char delim) { + char *q; + + if (res == NULL || ptr == NULL || *ptr == NULL) { + errno = EINVAL; + return (NULL); + } + + q = strchr(*ptr, delim); + + if (q == NULL) { + errno = EINVAL; + return (NULL); + } else { + if (*res == NULL) { + *res = strndup(*ptr, q - *ptr); + } else { + if ((size_t)(q - *ptr + 1) > reslen) { /*%< to big for res */ + errno = EINVAL; + return (NULL); + } else { + strncpy(*res, *ptr, q - *ptr); + (*res)[q - *ptr] = 0x0; + } + } + *ptr = q + 1; + } + + return (*res); +} + + + + + +#ifndef HAVE_STRNDUP +/* + * static char * strndup(const char *str, size_t len) + * + * notes: \li + * + * like strdup, except do len bytes instead of the whole string. Always + * null-terminates. + * + * return: \li + * + * The newly malloced string. + * + */ + +static char * +strndup(const char *str, size_t len) { + char *p = malloc(len + 1); + + if (p == NULL) + return (NULL); + strncpy(p, str, len); + p[len] = 0x0; + return (p); +} +#endif + +#if WANT_MAIN + +/*% + * static int strcmp_nws(const char *a, const char *b) + * + * notes: \li + * + * do a strcmp, except uneven lengths of whitespace compare the same + * + * return: \li + * + */ + +static int +strcmp_nws(const char *a, const char *b) { + while (*a && *b) { + if (isspace(*a) && isspace(*b)) { + do { + a++; + } while (isspace(*a)); + do { + b++; + } while (isspace(*b)); + } + if (*a < *b) + return (-1); + else if (*a > *b) + return (1); + + a++; + b++;; + } + + if (*a == *b) + return (0); + else if (*a > *b) + return (1); + else + return (-1); +} + +#endif + +/*% + * static void free_array(char **argv, size_t entries) + * + * notes: \li + * + * Free argv and each of the pointers inside it. The end of + * the array is when a NULL pointer is found inside. If + * entries is > 0, then NULL pointers inside the array do + * not indicate the end of the array. + * + */ + +static void +free_array(char **argv, size_t entries) { + char **p = argv; + int useEntries = (entries > 0U); + + if (argv == NULL) + return; + + while ((useEntries && entries > 0U) || *p) { + if (*p) + free(*p); + p++; + if (useEntries) + entries--; + } + free(argv); +} + + + + + +/* ************************************************** */ + +#if WANT_MAIN + +/*% takes an option to indicate what sort of marshalling(read the code) and + an argument. If the argument looks like a marshalled buffer(has a ':' + embedded) then it's unmarshalled and the remarshalled and the new string + is compared to the old one. +*/ + +int +main(int argc, char **argv) { + char buffer[1024]; + char *b = &buffer[0]; + size_t len = sizeof buffer; + char option; + + if (argc < 2 || argv[1][0] != '-') + exit(1); + + option = argv[1][1]; + argv++; + argc--; + + +#if 0 + { + char buff[10]; + char *p = argv[1], *q = &buff[0]; + + while (getfield(&q, sizeof buff, &p, ':') != NULL) { + printf("field: \"%s\"\n", q); + p++; + } + printf("p is now \"%s\"\n", p); + } +#endif + +#if 0 + { + char **x = splitarray(argv[1], argv[1] + strlen(argv[1]), + argv[2][0]); + char **p; + + if (x == NULL) + printf("split failed\n"); + + for (p = x ; p != NULL && *p != NULL ; p++) { + printf("\"%s\"\n", *p); + } + } +#endif + +#if 1 + switch(option) { + case 'n': { + struct nwent ne; + int i; + + if (strchr(argv[1], ':') != NULL) { + if (irp_unmarshall_nw(&ne, argv[1]) != 0) { + printf("Unmarhsalling failed\n"); + exit(1); + } + + printf("Name: \"%s\"\n", ne.n_name); + printf("Aliases:"); + for (i = 0 ; ne.n_aliases[i] != NULL ; i++) + printf("\n\t\"%s\"", ne.n_aliases[i]); + printf("\nAddrtype: %s\n", ADDR_T_STR(ne.n_addrtype)); + inet_net_ntop(ne.n_addrtype, ne.n_addr, ne.n_length, + buffer, sizeof buffer); + printf("Net: \"%s\"\n", buffer); + *((long*)ne.n_addr) = htonl(*((long*)ne.n_addr)); + inet_net_ntop(ne.n_addrtype, ne.n_addr, ne.n_length, + buffer, sizeof buffer); + printf("Corrected Net: \"%s\"\n", buffer); + } else { + struct netent *np1 = getnetbyname(argv[1]); + ne.n_name = np1->n_name; + ne.n_aliases = np1->n_aliases; + ne.n_addrtype = np1->n_addrtype; + ne.n_addr = &np1->n_net; + ne.n_length = (IN_CLASSA(np1->n_net) ? + 8 : + (IN_CLASSB(np1->n_net) ? + 16 : + (IN_CLASSC(np1->n_net) ? + 24 : -1))); + np1->n_net = htonl(np1->n_net); + if (irp_marshall_nw(&ne, &b, &len) != 0) { + printf("Marshalling failed\n"); + } + printf("%s\n", b); + } + break; + } + + + case 'r': { + char **hosts, **users, **domains; + size_t entries; + int i; + char *buff; + size_t size; + char *ngname; + + if (strchr(argv[1], '(') != NULL) { + if (irp_unmarshall_ng(&ngname, &entries, + &hosts, &users, &domains, + argv[1]) != 0) { + printf("unmarshall failed\n"); + exit(1); + } + +#define STRVAL(x) (x == NULL ? "*" : x) + + printf("%s {\n", ngname); + for (i = 0 ; i < entries ; i++) + printf("\t\"%s\" : \"%s\" : \"%s\"\n", + STRVAL(hosts[i]), + STRVAL(users[i]), + STRVAL(domains[i])); + printf("}\n\n\n"); + + + irp_marshall_ng_start(ngname, NULL, &size); + for (i = 0 ; i < entries ; i++) + irp_marshall_ng_next(hosts[i], users[i], + domains[i], NULL, &size); + irp_marshall_ng_end(NULL, &size); + + buff = malloc(size); + + irp_marshall_ng_start(ngname, buff, &size); + for (i = 0 ; i < entries ; i++) { + if (irp_marshall_ng_next(hosts[i], users[i], + domains[i], buff, + &size) != 0) + printf("next marshalling failed.\n"); + } + irp_marshall_ng_end(buff, &size); + + if (strcmp_nws(argv[1], buff) != 0) { + printf("compare failed:\n\t%s\n\t%s\n", + buffer, argv[1]); + } else { + printf("compare ok\n"); + } + } else { + char *h, *u, *d, *buff; + size_t size; + + /* run through two times. First to figure out how + much of a buffer we need. Second to do the + actual marshalling */ + + setnetgrent(argv[1]); + irp_marshall_ng_start(argv[1], NULL, &size); + while (getnetgrent(&h, &u, &d) == 1) + irp_marshall_ng_next(h, u, d, NULL, &size); + irp_marshall_ng_end(NULL, &size); + endnetgrent(argv[1]); + + buff = malloc(size); + + setnetgrent(argv[1]); + if (irp_marshall_ng_start(argv[1], buff, &size) != 0) + printf("Marshalling start failed\n"); + + while (getnetgrent(&h, &u, &d) == 1) { + if (irp_marshall_ng_next(h, u, d, buff, &size) + != 0) { + printf("Marshalling failed\n"); + } + } + + irp_marshall_ng_end(buff, &size); + endnetgrent(); + + printf("success: %s\n", buff); + } + break; + } + + + + case 'h': { + struct hostent he, *hp; + int i; + + + if (strchr(argv[1], '@') != NULL) { + if (irp_unmarshall_ho(&he, argv[1]) != 0) { + printf("unmarshall failed\n"); + exit(1); + } + + printf("Host: \"%s\"\nAliases:", he.h_name); + for (i = 0 ; he.h_aliases[i] != NULL ; i++) + printf("\n\t\t\"%s\"", he.h_aliases[i]); + printf("\nAddr Type: \"%s\"\n", + ADDR_T_STR(he.h_addrtype)); + printf("Length: %d\nAddresses:", he.h_length); + for (i = 0 ; he.h_addr_list[i] != 0 ; i++) { + inet_ntop(he.h_addrtype, he.h_addr_list[i], + buffer, sizeof buffer); + printf("\n\t\"%s\"\n", buffer); + } + printf("\n\n"); + + irp_marshall_ho(&he, &b, &len); + if (strcmp(argv[1], buffer) != 0) { + printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n", + buffer, argv[1]); + } else { + printf("compare ok\n"); + } + } else { + if ((hp = gethostbyname(argv[1])) == NULL) { + perror("gethostbyname"); + printf("\"%s\"\n", argv[1]); + exit(1); + } + + if (irp_marshall_ho(hp, &b, &len) != 0) { + printf("irp_marshall_ho failed\n"); + exit(1); + } + + printf("success: \"%s\"\n", buffer); + } + break; + } + + + case 's': { + struct servent *sv; + struct servent sv1; + + if (strchr(argv[1], ':') != NULL) { + sv = &sv1; + memset(sv, 0xef, sizeof (struct servent)); + if (irp_unmarshall_sv(sv, argv[1]) != 0) { + printf("unmarshall failed\n"); + + } + + irp_marshall_sv(sv, &b, &len); + if (strcmp(argv[1], buffer) != 0) { + printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n", + buffer, argv[1]); + } else { + printf("compare ok\n"); + } + } else { + if ((sv = getservbyname(argv[1], argv[2])) == NULL) { + perror("getservent"); + exit(1); + } + + if (irp_marshall_sv(sv, &b, &len) != 0) { + printf("irp_marshall_sv failed\n"); + exit(1); + } + + printf("success: \"%s\"\n", buffer); + } + break; + } + + case 'g': { + struct group *gr; + struct group gr1; + + if (strchr(argv[1], ':') != NULL) { + gr = &gr1; + memset(gr, 0xef, sizeof (struct group)); + if (irp_unmarshall_gr(gr, argv[1]) != 0) { + printf("unmarshall failed\n"); + + } + + irp_marshall_gr(gr, &b, &len); + if (strcmp(argv[1], buffer) != 0) { + printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n", + buffer, argv[1]); + } else { + printf("compare ok\n"); + } + } else { + if ((gr = getgrnam(argv[1])) == NULL) { + perror("getgrnam"); + exit(1); + } + + if (irp_marshall_gr(gr, &b, &len) != 0) { + printf("irp_marshall_gr failed\n"); + exit(1); + } + + printf("success: \"%s\"\n", buffer); + } + break; + } + + + case 'p': { + struct passwd *pw; + struct passwd pw1; + + if (strchr(argv[1], ':') != NULL) { + pw = &pw1; + memset(pw, 0xef, sizeof (*pw)); + if (irp_unmarshall_pw(pw, argv[1]) != 0) { + printf("unmarshall failed\n"); + exit(1); + } + + printf("User: \"%s\"\nPasswd: \"%s\"\nUid: %ld\nGid: %ld\n", + pw->pw_name, pw->pw_passwd, (long)pw->pw_uid, + (long)pw->pw_gid); + printf("Class: \"%s\"\nChange: %ld\nGecos: \"%s\"\n", + pw->pw_class, (long)pw->pw_change, pw->pw_gecos); + printf("Shell: \"%s\"\nDirectory: \"%s\"\n", + pw->pw_shell, pw->pw_dir); + + pw = getpwnam(pw->pw_name); + irp_marshall_pw(pw, &b, &len); + if (strcmp(argv[1], buffer) != 0) { + printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n", + buffer, argv[1]); + } else { + printf("compare ok\n"); + } + } else { + if ((pw = getpwnam(argv[1])) == NULL) { + perror("getpwnam"); + exit(1); + } + + if (irp_marshall_pw(pw, &b, &len) != 0) { + printf("irp_marshall_pw failed\n"); + exit(1); + } + + printf("success: \"%s\"\n", buffer); + } + break; + } + + default: + printf("Wrong option: %c\n", option); + break; + } + +#endif + + return (0); +} + +#endif + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/irs_data.c b/contrib/bind-9.5.2/lib/bind/irs/irs_data.c new file mode 100644 index 0000000000..cd8ba00c50 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/irs_data.c @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: irs_data.c,v 1.12 2007/08/27 03:32:26 marka Exp $"; +#endif + +#include "port_before.h" + +#ifndef __BIND_NOSTATIC + +#include + +#include +#include + +#include +#include +#include +#include + +#ifdef DO_PTHREADS +#include +#endif + +#include +#include + +#include "port_after.h" + +#include "irs_data.h" +#undef _res +#if !(__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) +#undef h_errno +extern int h_errno; +#endif + +extern struct __res_state _res; + +#ifdef DO_PTHREADS +static pthread_key_t key; +static int once = 0; +#else +static struct net_data *net_data; +#endif + +void +irs_destroy(void) { +#ifndef DO_PTHREADS + if (net_data != NULL) + net_data_destroy(net_data); + net_data = NULL; +#endif +} + +void +net_data_destroy(void *p) { + struct net_data *net_data = p; + + res_ndestroy(net_data->res); + if (net_data->gr != NULL) { + (*net_data->gr->close)(net_data->gr); + net_data->gr = NULL; + } + if (net_data->pw != NULL) { + (*net_data->pw->close)(net_data->pw); + net_data->pw = NULL; + } + if (net_data->sv != NULL) { + (*net_data->sv->close)(net_data->sv); + net_data->sv = NULL; + } + if (net_data->pr != NULL) { + (*net_data->pr->close)(net_data->pr); + net_data->pr = NULL; + } + if (net_data->ho != NULL) { + (*net_data->ho->close)(net_data->ho); + net_data->ho = NULL; + } + if (net_data->nw != NULL) { + (*net_data->nw->close)(net_data->nw); + net_data->nw = NULL; + } + if (net_data->ng != NULL) { + (*net_data->ng->close)(net_data->ng); + net_data->ng = NULL; + } + if (net_data->ho_data != NULL) { + free(net_data->ho_data); + net_data->ho_data = NULL; + } + if (net_data->nw_data != NULL) { + free(net_data->nw_data); + net_data->nw_data = NULL; + } + + (*net_data->irs->close)(net_data->irs); + memput(net_data, sizeof *net_data); +} + +/*% + * applications that need a specific config file other than + * _PATH_IRS_CONF should call net_data_init directly rather than letting + * the various wrapper functions make the first call. - brister + */ + +struct net_data * +net_data_init(const char *conf_file) { +#ifdef DO_PTHREADS +#ifndef LIBBIND_MUTEX_INITIALIZER +#define LIBBIND_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +#endif + static pthread_mutex_t keylock = LIBBIND_MUTEX_INITIALIZER; + struct net_data *net_data; + + if (!once) { + if (pthread_mutex_lock(&keylock) != 0) + return (NULL); + if (!once) { + if (pthread_key_create(&key, net_data_destroy) != 0) { + (void)pthread_mutex_unlock(&keylock); + return (NULL); + } + once = 1; + } + if (pthread_mutex_unlock(&keylock) != 0) + return (NULL); + } + net_data = pthread_getspecific(key); +#endif + + if (net_data == NULL) { + net_data = net_data_create(conf_file); + if (net_data == NULL) + return (NULL); +#ifdef DO_PTHREADS + if (pthread_setspecific(key, net_data) != 0) { + net_data_destroy(net_data); + return (NULL); + } +#endif + } + + return (net_data); +} + +struct net_data * +net_data_create(const char *conf_file) { + struct net_data *net_data; + + net_data = memget(sizeof (struct net_data)); + if (net_data == NULL) + return (NULL); + memset(net_data, 0, sizeof (struct net_data)); + + if ((net_data->irs = irs_gen_acc("", conf_file)) == NULL) { + memput(net_data, sizeof (struct net_data)); + return (NULL); + } +#ifndef DO_PTHREADS + (*net_data->irs->res_set)(net_data->irs, &_res, NULL); +#endif + + net_data->res = (*net_data->irs->res_get)(net_data->irs); + if (net_data->res == NULL) { + (*net_data->irs->close)(net_data->irs); + memput(net_data, sizeof (struct net_data)); + return (NULL); + } + + if ((net_data->res->options & RES_INIT) == 0U && + res_ninit(net_data->res) == -1) { + (*net_data->irs->close)(net_data->irs); + memput(net_data, sizeof (struct net_data)); + return (NULL); + } + + return (net_data); +} + +void +net_data_minimize(struct net_data *net_data) { + res_nclose(net_data->res); +} + +#ifdef _REENTRANT +struct __res_state * +__res_state(void) { + /* NULL param here means use the default config file. */ + struct net_data *net_data = net_data_init(NULL); + if (net_data && net_data->res) + return (net_data->res); + + return (&_res); +} +#else +#ifdef __linux +struct __res_state * +__res_state(void) { + return (&_res); +} +#endif +#endif + +int * +__h_errno(void) { + /* NULL param here means use the default config file. */ + struct net_data *net_data = net_data_init(NULL); + if (net_data && net_data->res) + return (&net_data->res->res_h_errno); +#if !(__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) + return(&_res.res_h_errno); +#else + return (&h_errno); +#endif +} + +void +__h_errno_set(struct __res_state *res, int err) { + + +#if (__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) + res->res_h_errno = err; +#else + h_errno = res->res_h_errno = err; +#endif +} + +#endif /*__BIND_NOSTATIC*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/irs_data.h b/contrib/bind-9.5.2/lib/bind/irs/irs_data.h new file mode 100644 index 0000000000..cb814fd8b1 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/irs_data.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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: irs_data.h,v 1.3 2005/04/27 04:56:30 sra Exp $ + */ + +#ifndef __BIND_NOSTATIC + +#define net_data_init __net_data_init + +struct net_data { + struct irs_acc * irs; + + struct irs_gr * gr; + struct irs_pw * pw; + struct irs_sv * sv; + struct irs_pr * pr; + struct irs_ho * ho; + struct irs_nw * nw; + struct irs_ng * ng; + + struct group * gr_last; + struct passwd * pw_last; + struct servent * sv_last; + struct protoent * pr_last; + struct netent * nw_last; /*%< should have been ne_last */ + struct nwent * nww_last; + struct hostent * ho_last; + + unsigned int gr_stayopen :1; + unsigned int pw_stayopen :1; + unsigned int sv_stayopen :1; + unsigned int pr_stayopen :1; + unsigned int ho_stayopen :1; + unsigned int nw_stayopen :1; + + void * nw_data; + void * ho_data; + + struct __res_state * res; /*%< for gethostent.c */ +}; + +extern struct net_data * net_data_init(const char *conf_file); +extern void net_data_minimize(struct net_data *); + +#endif /*__BIND_NOSTATIC*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/irs_p.h b/contrib/bind-9.5.2/lib/bind/irs/irs_p.h new file mode 100644 index 0000000000..2a0a933fce --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/irs_p.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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: irs_p.h,v 1.3 2005/04/27 04:56:30 sra Exp $ + */ + +#ifndef _IRS_P_H_INCLUDED +#define _IRS_P_H_INCLUDED + +#include + +#include "pathnames.h" + +#define IRS_SV_MAXALIASES 35 + +struct lcl_sv { + FILE * fp; + char line[BUFSIZ+1]; + struct servent serv; + char * serv_aliases[IRS_SV_MAXALIASES]; +}; + +#define irs_nul_ng __irs_nul_ng +#define map_v4v6_address __map_v4v6_address +#define make_group_list __make_group_list +#define irs_lclsv_fnxt __irs_lclsv_fnxt + +extern void map_v4v6_address(const char *src, char *dst); +extern int make_group_list(struct irs_gr *, const char *, + gid_t, gid_t *, int *); +extern struct irs_ng * irs_nul_ng(struct irs_acc *); +extern struct servent * irs_lclsv_fnxt(struct lcl_sv *); + +#endif + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/lcl.c b/contrib/bind-9.5.2/lib/bind/irs/lcl.c new file mode 100644 index 0000000000..ea78a258a6 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/lcl.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: lcl.c,v 1.4 2005/04/27 04:56:30 sra Exp $"; +#endif + +/* Imports */ + +#include "port_before.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "lcl_p.h" + +/* Forward. */ + +static void lcl_close(struct irs_acc *); +static struct __res_state * lcl_res_get(struct irs_acc *); +static void lcl_res_set(struct irs_acc *, struct __res_state *, + void (*)(void *)); + +/* Public */ + +struct irs_acc * +irs_lcl_acc(const char *options) { + struct irs_acc *acc; + struct lcl_p *lcl; + + UNUSED(options); + + if (!(acc = memget(sizeof *acc))) { + errno = ENOMEM; + return (NULL); + } + memset(acc, 0x5e, sizeof *acc); + if (!(lcl = memget(sizeof *lcl))) { + errno = ENOMEM; + free(acc); + return (NULL); + } + memset(lcl, 0x5e, sizeof *lcl); + lcl->res = NULL; + lcl->free_res = NULL; + acc->private = lcl; +#ifdef WANT_IRS_GR + acc->gr_map = irs_lcl_gr; +#else + acc->gr_map = NULL; +#endif +#ifdef WANT_IRS_PW + acc->pw_map = irs_lcl_pw; +#else + acc->pw_map = NULL; +#endif + acc->sv_map = irs_lcl_sv; + acc->pr_map = irs_lcl_pr; + acc->ho_map = irs_lcl_ho; + acc->nw_map = irs_lcl_nw; + acc->ng_map = irs_lcl_ng; + acc->res_get = lcl_res_get; + acc->res_set = lcl_res_set; + acc->close = lcl_close; + return (acc); +} + +/* Methods */ +static struct __res_state * +lcl_res_get(struct irs_acc *this) { + struct lcl_p *lcl = (struct lcl_p *)this->private; + + if (lcl->res == NULL) { + struct __res_state *res; + res = (struct __res_state *)malloc(sizeof *res); + if (res == NULL) + return (NULL); + memset(res, 0, sizeof *res); + lcl_res_set(this, res, free); + } + + if ((lcl->res->options & RES_INIT) == 0U && + res_ninit(lcl->res) < 0) + return (NULL); + + return (lcl->res); +} + +static void +lcl_res_set(struct irs_acc *this, struct __res_state *res, + void (*free_res)(void *)) { + struct lcl_p *lcl = (struct lcl_p *)this->private; + + if (lcl->res && lcl->free_res) { + res_nclose(lcl->res); + (*lcl->free_res)(lcl->res); + } + + lcl->res = res; + lcl->free_res = free_res; +} + +static void +lcl_close(struct irs_acc *this) { + struct lcl_p *lcl = (struct lcl_p *)this->private; + + if (lcl) { + if (lcl->free_res) + (*lcl->free_res)(lcl->res); + memput(lcl, sizeof *lcl); + } + memput(this, sizeof *this); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/lcl_gr.c b/contrib/bind-9.5.2/lib/bind/irs/lcl_gr.c new file mode 100644 index 0000000000..ce7e347b2d --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/lcl_gr.c @@ -0,0 +1,354 @@ +/* + * Copyright (c) 1989, 1993, 1995 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: lcl_gr.c,v 1.3 2005/04/27 04:56:30 sra Exp $"; +/* from getgrent.c 8.2 (Berkeley) 3/21/94"; */ +/* from BSDI Id: getgrent.c,v 2.8 1996/05/28 18:15:14 bostic Exp $ */ +#endif /* LIBC_SCCS and not lint */ + +/* extern */ + +#include "port_before.h" + +#ifndef WANT_IRS_PW +static int __bind_irs_gr_unneeded; +#else + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "irs_p.h" +#include "lcl_p.h" +#include "irp_p.h" + +#include "port_after.h" + + +/* Types. */ + +struct pvt { + FILE * fp; + /*%< + * Need space to store the entries read from the group file. + * The members list also needs space per member, and the + * strings making up the user names must be allocated + * somewhere. Rather than doing lots of small allocations, + * we keep one buffer and resize it as needed. + */ + struct group group; + size_t nmemb; /*%< Malloc'd max index of gr_mem[]. */ + char * membuf; + size_t membufsize; +}; + +/* Forward. */ + +static void gr_close(struct irs_gr *); +static struct group * gr_next(struct irs_gr *); +static struct group * gr_byname(struct irs_gr *, const char *); +static struct group * gr_bygid(struct irs_gr *, gid_t); +static void gr_rewind(struct irs_gr *); +static void gr_minimize(struct irs_gr *); + +static int grstart(struct pvt *); +static char * grnext(struct pvt *); +static struct group * grscan(struct irs_gr *, int, gid_t, const char *); + +/* Portability. */ + +#ifndef SEEK_SET +# define SEEK_SET 0 +#endif + +/* Public. */ + +struct irs_gr * +irs_lcl_gr(struct irs_acc *this) { + struct irs_gr *gr; + struct pvt *pvt; + + UNUSED(this); + + if (!(gr = memget(sizeof *gr))) { + errno = ENOMEM; + return (NULL); + } + memset(gr, 0x5e, sizeof *gr); + if (!(pvt = memget(sizeof *pvt))) { + memput(gr, sizeof *gr); + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + gr->private = pvt; + gr->close = gr_close; + gr->next = gr_next; + gr->byname = gr_byname; + gr->bygid = gr_bygid; + gr->rewind = gr_rewind; + gr->list = make_group_list; + gr->minimize = gr_minimize; + gr->res_get = NULL; + gr->res_set = NULL; + return (gr); +} + +/* Methods. */ + +static void +gr_close(struct irs_gr *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->fp) + (void)fclose(pvt->fp); + if (pvt->group.gr_mem) + free(pvt->group.gr_mem); + if (pvt->membuf) + free(pvt->membuf); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct group * +gr_next(struct irs_gr *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->fp && !grstart(pvt)) + return (NULL); + return (grscan(this, 0, 0, NULL)); +} + +static struct group * +gr_byname(struct irs_gr *this, const char *name) { + if (!grstart((struct pvt *)this->private)) + return (NULL); + return (grscan(this, 1, 0, name)); +} + +static struct group * +gr_bygid(struct irs_gr *this, gid_t gid) { + if (!grstart((struct pvt *)this->private)) + return (NULL); + return (grscan(this, 1, gid, NULL)); +} + +static void +gr_rewind(struct irs_gr *this) { + (void) grstart((struct pvt *)this->private); +} + +static void +gr_minimize(struct irs_gr *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->fp != NULL) { + (void)fclose(pvt->fp); + pvt->fp = NULL; + } +} + +/* Private. */ + +static int +grstart(struct pvt *pvt) { + if (pvt->fp) { + if (fseek(pvt->fp, 0L, SEEK_SET) == 0) + return (1); + (void)fclose(pvt->fp); + } + if (!(pvt->fp = fopen(_PATH_GROUP, "r"))) + return (0); + if (fcntl(fileno(pvt->fp), F_SETFD, 1) < 0) { + fclose(pvt->fp); + return (0); + } + return (1); +} + +#define INITIAL_NMEMB 30 /*%< about 120 bytes */ +#define INITIAL_BUFSIZ (INITIAL_NMEMB * 8) /*%< about 240 bytes */ +static char * +grnext(struct pvt *pvt) { + char *w, *e; + int ch; + + /* Make sure we have a buffer. */ + if (pvt->membuf == NULL) { + pvt->membuf = malloc(INITIAL_BUFSIZ); + if (pvt->membuf == NULL) { + enomem: + errno = ENOMEM; + return (NULL); + } + pvt->membufsize = INITIAL_BUFSIZ; + } + + /* Read until EOF or EOL. */ + w = pvt->membuf; + e = pvt->membuf + pvt->membufsize; + while ((ch = fgetc(pvt->fp)) != EOF && ch != '\n') { + /* Make sure we have room for this character and a \0. */ + if (w + 1 == e) { + size_t o = w - pvt->membuf; + size_t n = pvt->membufsize * 2; + char *t = realloc(pvt->membuf, n); + + if (t == NULL) + goto enomem; + pvt->membuf = t; + pvt->membufsize = n; + w = pvt->membuf + o; + e = pvt->membuf + pvt->membufsize; + } + /* Store it. */ + *w++ = (char)ch; + } + + /* Hitting EOF on the first character really does mean EOF. */ + if (w == pvt->membuf && ch == EOF) { + errno = ENOENT; + return (NULL); + } + + /* Last line of /etc/group need not end with \n; we don't care. */ + *w = '\0'; + return (pvt->membuf); +} + +static struct group * +grscan(struct irs_gr *this, int search, gid_t gid, const char *name) { + struct pvt *pvt = (struct pvt *)this->private; + size_t n; + char *bp, **m, *p; + + /* Read lines until we find one that matches our search criteria. */ + for (;;) { + if ((bp = grnext(pvt)) == NULL) + return (NULL); + + /* Optimize the usual case of searching for a name. */ + pvt->group.gr_name = strsep(&bp, ":"); + if (search && name != NULL && + strcmp(pvt->group.gr_name, name) != 0) + continue; + if (bp == NULL || *bp == '\0') + goto corrupt; + + /* Skip past the password field. */ + pvt->group.gr_passwd = strsep(&bp, ":"); + if (bp == NULL || *bp == '\0') + goto corrupt; + + /* Checking for a gid. */ + if ((p = strsep(&bp, ":")) == NULL) + continue; + /* + * Unlike the tests above, the test below is supposed to be + * testing 'p' and not 'bp', in case you think it's a typo. + */ + if (p == NULL || *p == '\0') { + corrupt: + /* warning: corrupted %s file!", _PATH_GROUP */ + continue; + } + pvt->group.gr_gid = atoi(p); + if (search && name == NULL && (gid_t)pvt->group.gr_gid != gid) + continue; + + /* We want this record. */ + break; + } + + /* + * Count commas to find out how many members there might be. + * Note that commas separate, so if there is one comma there + * can be two members (group:*:id:user1,user2). Add another + * to account for the NULL terminator. As above, allocate + * largest of INITIAL_NMEMB, or 2*n. + */ + n = 1; + if (bp != NULL) + for (n = 2, p = bp; (p = strpbrk(p, ", ")) != NULL; ++n) + p += strspn(p, ", "); + if (n > pvt->nmemb || pvt->group.gr_mem == NULL) { + if ((n *= 2) < INITIAL_NMEMB) + n = INITIAL_NMEMB; + if ((m = realloc(pvt->group.gr_mem, n * sizeof *m)) == NULL) + return (NULL); + pvt->group.gr_mem = m; + pvt->nmemb = n; + } + + /* Set the name pointers. */ + for (m = pvt->group.gr_mem; (p = strsep(&bp, ", ")) != NULL;) + if (p[0] != '\0') + *m++ = p; + *m = NULL; + + return (&pvt->group); +} + +#endif /* WANT_IRS_GR */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/lcl_ho.c b/contrib/bind-9.5.2/lib/bind/irs/lcl_ho.c new file mode 100644 index 0000000000..6c5246a5c4 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/lcl_ho.c @@ -0,0 +1,578 @@ +/* + * Copyright (c) 1985, 1988, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +/* from gethostnamadr.c 8.1 (Berkeley) 6/4/93 */ +/* BIND Id: gethnamaddr.c,v 8.15 1996/05/22 04:56:30 vixie Exp $ */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: lcl_ho.c,v 1.5 2006/03/09 23:57:56 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* Imports. */ + +#include "port_before.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "dns_p.h" +#include "lcl_p.h" + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) sprintf x +#endif + +/* Definitions. */ + +#define MAXALIASES 35 +#define MAXADDRS 35 +#define Max(a,b) ((a) > (b) ? (a) : (b)) + +#if PACKETSZ > 1024 +#define MAXPACKET PACKETSZ +#else +#define MAXPACKET 1024 +#endif + +struct pvt { + FILE * fp; + struct hostent host; + char * h_addr_ptrs[MAXADDRS + 1]; + char * host_aliases[MAXALIASES]; + char hostbuf[8*1024]; + u_char host_addr[16]; /*%< IPv4 or IPv6 */ + struct __res_state *res; + void (*free_res)(void *); +}; + +typedef union { + int32_t al; + char ac; +} align; + +static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff }; +static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 }; + +/* Forward. */ + +static void ho_close(struct irs_ho *this); +static struct hostent * ho_byname(struct irs_ho *this, const char *name); +static struct hostent * ho_byname2(struct irs_ho *this, const char *name, + int af); +static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr, + int len, int af); +static struct hostent * ho_next(struct irs_ho *this); +static void ho_rewind(struct irs_ho *this); +static void ho_minimize(struct irs_ho *this); +static struct __res_state * ho_res_get(struct irs_ho *this); +static void ho_res_set(struct irs_ho *this, + struct __res_state *res, + void (*free_res)(void *)); +static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name, + const struct addrinfo *pai); + +static size_t ns_namelen(const char *); +static int init(struct irs_ho *this); + +/* Portability. */ + +#ifndef SEEK_SET +# define SEEK_SET 0 +#endif + +/* Public. */ + +struct irs_ho * +irs_lcl_ho(struct irs_acc *this) { + struct irs_ho *ho; + struct pvt *pvt; + + UNUSED(this); + + if (!(pvt = memget(sizeof *pvt))) { + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + if (!(ho = memget(sizeof *ho))) { + memput(pvt, sizeof *pvt); + errno = ENOMEM; + return (NULL); + } + memset(ho, 0x5e, sizeof *ho); + ho->private = pvt; + ho->close = ho_close; + ho->byname = ho_byname; + ho->byname2 = ho_byname2; + ho->byaddr = ho_byaddr; + ho->next = ho_next; + ho->rewind = ho_rewind; + ho->minimize = ho_minimize; + ho->res_get = ho_res_get; + ho->res_set = ho_res_set; + ho->addrinfo = ho_addrinfo; + return (ho); +} + +/* Methods. */ + +static void +ho_close(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + + ho_minimize(this); + if (pvt->fp) + (void) fclose(pvt->fp); + if (pvt->res && pvt->free_res) + (*pvt->free_res)(pvt->res); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct hostent * +ho_byname(struct irs_ho *this, const char *name) { + struct pvt *pvt = (struct pvt *)this->private; + struct hostent *hp; + + if (init(this) == -1) + return (NULL); + + if (pvt->res->options & RES_USE_INET6) { + hp = ho_byname2(this, name, AF_INET6); + if (hp) + return (hp); + } + return (ho_byname2(this, name, AF_INET)); +} + +static struct hostent * +ho_byname2(struct irs_ho *this, const char *name, int af) { + struct pvt *pvt = (struct pvt *)this->private; + struct hostent *hp; + char **hap; + size_t n; + + if (init(this) == -1) + return (NULL); + + ho_rewind(this); + n = ns_namelen(name); + while ((hp = ho_next(this)) != NULL) { + size_t nn; + + if (hp->h_addrtype != af) + continue; + nn = ns_namelen(hp->h_name); + if (strncasecmp(hp->h_name, name, Max(n, nn)) == 0) + goto found; + for (hap = hp->h_aliases; *hap; hap++) { + nn = ns_namelen(*hap); + if (strncasecmp(*hap, name, Max(n, nn)) == 0) + goto found; + } + } + found: + if (!hp) { + RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); + return (NULL); + } + RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS); + return (hp); +} + +static struct hostent * +ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) { + struct pvt *pvt = (struct pvt *)this->private; + const u_char *uaddr = addr; + struct hostent *hp; + int size; + + if (init(this) == -1) + return (NULL); + + if (af == AF_INET6 && len == IN6ADDRSZ && + (!memcmp(uaddr, mapped, sizeof mapped) || + !memcmp(uaddr, tunnelled, sizeof tunnelled))) { + /* Unmap. */ + addr = (const u_char *)addr + sizeof mapped; + uaddr += sizeof mapped; + af = AF_INET; + len = INADDRSZ; + } + switch (af) { + case AF_INET: + size = INADDRSZ; + break; + case AF_INET6: + size = IN6ADDRSZ; + break; + default: + errno = EAFNOSUPPORT; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + return (NULL); + } + if (size > len) { + errno = EINVAL; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + return (NULL); + } + + /* + * Do the search. + */ + ho_rewind(this); + while ((hp = ho_next(this)) != NULL) { + char **hap; + + for (hap = hp->h_addr_list; *hap; hap++) { + const u_char *taddr = (const u_char *)*hap; + int taf = hp->h_addrtype; + int tlen = hp->h_length; + + if (taf == AF_INET6 && tlen == IN6ADDRSZ && + (!memcmp(taddr, mapped, sizeof mapped) || + !memcmp(taddr, tunnelled, sizeof tunnelled))) { + /* Unmap. */ + taddr += sizeof mapped; + taf = AF_INET; + tlen = INADDRSZ; + } + if (taf == af && tlen == len && + !memcmp(taddr, uaddr, tlen)) + goto found; + } + } + found: + if (!hp) { + RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); + return (NULL); + } + RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS); + return (hp); +} + +static struct hostent * +ho_next(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + char *cp, **q, *p; + char *bufp, *ndbuf, *dbuf = NULL; + int c, af, len, bufsiz, offset; + + if (init(this) == -1) + return (NULL); + + if (!pvt->fp) + ho_rewind(this); + if (!pvt->fp) { + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + return (NULL); + } + bufp = pvt->hostbuf; + bufsiz = sizeof pvt->hostbuf; + offset = 0; + again: + if (!(p = fgets(bufp + offset, bufsiz - offset, pvt->fp))) { + RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); + if (dbuf) + free(dbuf); + return (NULL); + } + if (!strchr(p, '\n') && !feof(pvt->fp)) { +#define GROWBUF 1024 + /* allocate space for longer line */ + if (dbuf == NULL) { + if ((ndbuf = malloc(bufsiz + GROWBUF)) != NULL) + strcpy(ndbuf, bufp); + } else + ndbuf = realloc(dbuf, bufsiz + GROWBUF); + if (ndbuf) { + dbuf = ndbuf; + bufp = dbuf; + bufsiz += GROWBUF; + offset = strlen(dbuf); + } else { + /* allocation failed; skip this long line */ + while ((c = getc(pvt->fp)) != EOF) + if (c == '\n') + break; + if (c != EOF) + ungetc(c, pvt->fp); + } + goto again; + } + + p -= offset; + offset = 0; + + if (*p == '#') + goto again; + if ((cp = strpbrk(p, "#\n")) != NULL) + *cp = '\0'; + if (!(cp = strpbrk(p, " \t"))) + goto again; + *cp++ = '\0'; + if (inet_pton(AF_INET6, p, pvt->host_addr) > 0) { + af = AF_INET6; + len = IN6ADDRSZ; + } else if (inet_aton(p, (struct in_addr *)pvt->host_addr) > 0) { + if (pvt->res->options & RES_USE_INET6) { + map_v4v6_address((char*)pvt->host_addr, + (char*)pvt->host_addr); + af = AF_INET6; + len = IN6ADDRSZ; + } else { + af = AF_INET; + len = INADDRSZ; + } + } else { + goto again; + } + pvt->h_addr_ptrs[0] = (char *)pvt->host_addr; + pvt->h_addr_ptrs[1] = NULL; + pvt->host.h_addr_list = pvt->h_addr_ptrs; + pvt->host.h_length = len; + pvt->host.h_addrtype = af; + while (*cp == ' ' || *cp == '\t') + cp++; + pvt->host.h_name = cp; + q = pvt->host.h_aliases = pvt->host_aliases; + if ((cp = strpbrk(cp, " \t")) != NULL) + *cp++ = '\0'; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &pvt->host_aliases[MAXALIASES - 1]) + *q++ = cp; + if ((cp = strpbrk(cp, " \t")) != NULL) + *cp++ = '\0'; + } + *q = NULL; + if (dbuf) + free(dbuf); + RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS); + return (&pvt->host); +} + +static void +ho_rewind(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->fp) { + if (fseek(pvt->fp, 0L, SEEK_SET) == 0) + return; + (void)fclose(pvt->fp); + } + if (!(pvt->fp = fopen(_PATH_HOSTS, "r"))) + return; + if (fcntl(fileno(pvt->fp), F_SETFD, 1) < 0) { + (void)fclose(pvt->fp); + pvt->fp = NULL; + } +} + +static void +ho_minimize(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->fp != NULL) { + (void)fclose(pvt->fp); + pvt->fp = NULL; + } + if (pvt->res) + res_nclose(pvt->res); +} + +static struct __res_state * +ho_res_get(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->res) { + struct __res_state *res; + res = (struct __res_state *)malloc(sizeof *res); + if (!res) { + errno = ENOMEM; + return (NULL); + } + memset(res, 0, sizeof *res); + ho_res_set(this, res, free); + } + + return (pvt->res); +} + +static void +ho_res_set(struct irs_ho *this, struct __res_state *res, + void (*free_res)(void *)) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->res && pvt->free_res) { + res_nclose(pvt->res); + (*pvt->free_res)(pvt->res); + } + + pvt->res = res; + pvt->free_res = free_res; +} + +struct lcl_res_target { + struct lcl_res_target *next; + int family; +}; + +/* XXX */ +extern struct addrinfo *hostent2addrinfo __P((struct hostent *, + const struct addrinfo *pai)); + +static struct addrinfo * +ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai) +{ + struct pvt *pvt = (struct pvt *)this->private; + struct hostent *hp; + struct lcl_res_target q, q2, *p; + struct addrinfo sentinel, *cur; + + memset(&q, 0, sizeof(q2)); + memset(&q2, 0, sizeof(q2)); + memset(&sentinel, 0, sizeof(sentinel)); + cur = &sentinel; + + switch(pai->ai_family) { + case AF_UNSPEC: /*%< INET6 then INET4 */ + q.family = AF_INET6; + q.next = &q2; + q2.family = AF_INET; + break; + case AF_INET6: + q.family = AF_INET6; + break; + case AF_INET: + q.family = AF_INET; + break; + default: + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); /*%< ??? */ + return(NULL); + } + + for (p = &q; p; p = p->next) { + struct addrinfo *ai; + + hp = (*this->byname2)(this, name, p->family); + if (hp == NULL) { + /* byname2 should've set an appropriate error */ + continue; + } + if ((hp->h_name == NULL) || (hp->h_name[0] == 0) || + (hp->h_addr_list[0] == NULL)) { + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); + continue; + } + + ai = hostent2addrinfo(hp, pai); + if (ai) { + cur->ai_next = ai; + while (cur->ai_next) + cur = cur->ai_next; + } + } + + if (sentinel.ai_next == NULL) + RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); + + return(sentinel.ai_next); +} + +/* Private. */ + +static size_t +ns_namelen(const char *s) { + int i; + + for (i = strlen(s); i > 0 && s[i-1] == '.'; i--) + (void)NULL; + return ((size_t) i); +} + +static int +init(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->res && !ho_res_get(this)) + return (-1); + if (((pvt->res->options & RES_INIT) == 0U) && + res_ninit(pvt->res) == -1) + return (-1); + return (0); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/lcl_ng.c b/contrib/bind-9.5.2/lib/bind/irs/lcl_ng.c new file mode 100644 index 0000000000..70e0b4563f --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/lcl_ng.c @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: lcl_ng.c,v 1.3 2005/04/27 04:56:31 sra Exp $"; +#endif + +/* Imports */ + +#include "port_before.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "lcl_p.h" + +/* Definitions */ + +#define NG_HOST 0 /*%< Host name */ +#define NG_USER 1 /*%< User name */ +#define NG_DOM 2 /*%< and Domain name */ +#define LINSIZ 1024 /*%< Length of netgroup file line */ +/* + * XXX Warning XXX + * This code is a hack-and-slash special. It realy needs to be + * rewritten with things like strdup, and realloc in mind. + * More reasonable data structures would not be a bad thing. + */ + +/*% + * Static Variables and functions used by setnetgrent(), getnetgrent() and + * endnetgrent(). + * + * There are two linked lists: + * \li linelist is just used by setnetgrent() to parse the net group file via. + * parse_netgrp() + * \li netgrp is the list of entries for the current netgroup + */ +struct linelist { + struct linelist *l_next; /*%< Chain ptr. */ + int l_parsed; /*%< Flag for cycles */ + char * l_groupname; /*%< Name of netgroup */ + char * l_line; /*%< Netgroup entrie(s) to be parsed */ +}; + +struct ng_old_struct { + struct ng_old_struct *ng_next; /*%< Chain ptr */ + char * ng_str[3]; /*%< Field pointers, see below */ +}; + +struct pvt { + FILE *fp; + struct linelist *linehead; + struct ng_old_struct *nextgrp; + struct { + struct ng_old_struct *gr; + char *grname; + } grouphead; +}; + +/* Forward */ + +static void ng_rewind(struct irs_ng *, const char*); +static void ng_close(struct irs_ng *); +static int ng_next(struct irs_ng *, const char **, + const char **, const char **); +static int ng_test(struct irs_ng *, const char *, + const char *, const char *, + const char *); +static void ng_minimize(struct irs_ng *); + +static int parse_netgrp(struct irs_ng *, const char*); +static struct linelist *read_for_group(struct irs_ng *, const char *); +static void freelists(struct irs_ng *); + +/* Public */ + +struct irs_ng * +irs_lcl_ng(struct irs_acc *this) { + struct irs_ng *ng; + struct pvt *pvt; + + UNUSED(this); + + if (!(ng = memget(sizeof *ng))) { + errno = ENOMEM; + return (NULL); + } + memset(ng, 0x5e, sizeof *ng); + if (!(pvt = memget(sizeof *pvt))) { + memput(ng, sizeof *ng); + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + ng->private = pvt; + ng->close = ng_close; + ng->next = ng_next; + ng->test = ng_test; + ng->rewind = ng_rewind; + ng->minimize = ng_minimize; + return (ng); +} + +/* Methods */ + +static void +ng_close(struct irs_ng *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->fp != NULL) + fclose(pvt->fp); + freelists(this); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +/*% + * Parse the netgroup file looking for the netgroup and build the list + * of netgrp structures. Let parse_netgrp() and read_for_group() do + * most of the work. + */ +static void +ng_rewind(struct irs_ng *this, const char *group) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->fp != NULL && fseek(pvt->fp, SEEK_CUR, 0L) == -1) { + fclose(pvt->fp); + pvt->fp = NULL; + } + + if (pvt->fp == NULL || pvt->grouphead.gr == NULL || + strcmp(group, pvt->grouphead.grname)) { + freelists(this); + if (pvt->fp != NULL) + fclose(pvt->fp); + pvt->fp = fopen(_PATH_NETGROUP, "r"); + if (pvt->fp != NULL) { + if (parse_netgrp(this, group)) + freelists(this); + if (!(pvt->grouphead.grname = strdup(group))) + freelists(this); + fclose(pvt->fp); + pvt->fp = NULL; + } + } + pvt->nextgrp = pvt->grouphead.gr; +} + +/*% + * Get the next netgroup off the list. + */ +static int +ng_next(struct irs_ng *this, const char **host, const char **user, + const char **domain) +{ + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->nextgrp) { + *host = pvt->nextgrp->ng_str[NG_HOST]; + *user = pvt->nextgrp->ng_str[NG_USER]; + *domain = pvt->nextgrp->ng_str[NG_DOM]; + pvt->nextgrp = pvt->nextgrp->ng_next; + return (1); + } + return (0); +} + +/*% + * Search for a match in a netgroup. + */ +static int +ng_test(struct irs_ng *this, const char *name, + const char *host, const char *user, const char *domain) +{ + const char *ng_host, *ng_user, *ng_domain; + + ng_rewind(this, name); + while (ng_next(this, &ng_host, &ng_user, &ng_domain)) + if ((host == NULL || ng_host == NULL || + !strcmp(host, ng_host)) && + (user == NULL || ng_user == NULL || + !strcmp(user, ng_user)) && + (domain == NULL || ng_domain == NULL || + !strcmp(domain, ng_domain))) { + freelists(this); + return (1); + } + freelists(this); + return (0); +} + +static void +ng_minimize(struct irs_ng *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->fp != NULL) { + (void)fclose(pvt->fp); + pvt->fp = NULL; + } +} + +/* Private */ + +/*% + * endnetgrent() - cleanup + */ +static void +freelists(struct irs_ng *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct linelist *lp, *olp; + struct ng_old_struct *gp, *ogp; + + lp = pvt->linehead; + while (lp) { + olp = lp; + lp = lp->l_next; + free(olp->l_groupname); + free(olp->l_line); + free((char *)olp); + } + pvt->linehead = NULL; + if (pvt->grouphead.grname) { + free(pvt->grouphead.grname); + pvt->grouphead.grname = NULL; + } + gp = pvt->grouphead.gr; + while (gp) { + ogp = gp; + gp = gp->ng_next; + if (ogp->ng_str[NG_HOST]) + free(ogp->ng_str[NG_HOST]); + if (ogp->ng_str[NG_USER]) + free(ogp->ng_str[NG_USER]); + if (ogp->ng_str[NG_DOM]) + free(ogp->ng_str[NG_DOM]); + free((char *)ogp); + } + pvt->grouphead.gr = NULL; +} + +/*% + * Parse the netgroup file setting up the linked lists. + */ +static int +parse_netgrp(struct irs_ng *this, const char *group) { + struct pvt *pvt = (struct pvt *)this->private; + char *spos, *epos; + int len, strpos; + char *pos, *gpos; + struct ng_old_struct *grp; + struct linelist *lp = pvt->linehead; + + /* + * First, see if the line has already been read in. + */ + while (lp) { + if (!strcmp(group, lp->l_groupname)) + break; + lp = lp->l_next; + } + if (lp == NULL && + (lp = read_for_group(this, group)) == NULL) + return (1); + if (lp->l_parsed) { + /*fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname);*/ + return (1); + } else + lp->l_parsed = 1; + pos = lp->l_line; + while (*pos != '\0') { + if (*pos == '(') { + if (!(grp = malloc(sizeof (struct ng_old_struct)))) { + freelists(this); + errno = ENOMEM; + return (1); + } + memset(grp, 0, sizeof (struct ng_old_struct)); + grp->ng_next = pvt->grouphead.gr; + pvt->grouphead.gr = grp; + pos++; + gpos = strsep(&pos, ")"); + for (strpos = 0; strpos < 3; strpos++) { + if ((spos = strsep(&gpos, ","))) { + while (*spos == ' ' || *spos == '\t') + spos++; + if ((epos = strpbrk(spos, " \t"))) { + *epos = '\0'; + len = epos - spos; + } else + len = strlen(spos); + if (len > 0) { + if(!(grp->ng_str[strpos] + = (char *) + malloc(len + 1))) { + freelists(this); + return (1); + } + memcpy(grp->ng_str[strpos], + spos, + len + 1); + } + } else + goto errout; + } + } else { + spos = strsep(&pos, ", \t"); + if (spos != NULL && parse_netgrp(this, spos)) { + freelists(this); + return (1); + } + } + if (pos == NULL) + break; + while (*pos == ' ' || *pos == ',' || *pos == '\t') + pos++; + } + return (0); + errout: + /*fprintf(stderr, "Bad netgroup %s at ..%s\n", lp->l_groupname, + spos);*/ + return (1); +} + +/*% + * Read the netgroup file and save lines until the line for the netgroup + * is found. Return 1 if eof is encountered. + */ +static struct linelist * +read_for_group(struct irs_ng *this, const char *group) { + struct pvt *pvt = (struct pvt *)this->private; + char *pos, *spos, *linep = NULL, *olinep; + int len, olen, cont; + struct linelist *lp; + char line[LINSIZ + 1]; + + while (fgets(line, LINSIZ, pvt->fp) != NULL) { + pos = line; + if (*pos == '#') + continue; + while (*pos == ' ' || *pos == '\t') + pos++; + spos = pos; + while (*pos != ' ' && *pos != '\t' && *pos != '\n' && + *pos != '\0') + pos++; + len = pos - spos; + while (*pos == ' ' || *pos == '\t') + pos++; + if (*pos != '\n' && *pos != '\0') { + if (!(lp = malloc(sizeof (*lp)))) { + freelists(this); + return (NULL); + } + lp->l_parsed = 0; + if (!(lp->l_groupname = malloc(len + 1))) { + free(lp); + freelists(this); + return (NULL); + } + memcpy(lp->l_groupname, spos, len); + *(lp->l_groupname + len) = '\0'; + len = strlen(pos); + olen = 0; + olinep = NULL; + + /* + * Loop around handling line continuations. + */ + do { + if (*(pos + len - 1) == '\n') + len--; + if (*(pos + len - 1) == '\\') { + len--; + cont = 1; + } else + cont = 0; + if (len > 0) { + if (!(linep = malloc(olen + len + 1))){ + if (olen > 0) + free(olinep); + free(lp->l_groupname); + free(lp); + freelists(this); + errno = ENOMEM; + return (NULL); + } + if (olen > 0) { + memcpy(linep, olinep, olen); + free(olinep); + } + memcpy(linep + olen, pos, len); + olen += len; + *(linep + olen) = '\0'; + olinep = linep; + } + if (cont) { + if (fgets(line, LINSIZ, pvt->fp)) { + pos = line; + len = strlen(pos); + } else + cont = 0; + } + } while (cont); + lp->l_line = linep; + lp->l_next = pvt->linehead; + pvt->linehead = lp; + + /* + * If this is the one we wanted, we are done. + */ + if (!strcmp(lp->l_groupname, group)) + return (lp); + } + } + return (NULL); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/lcl_nw.c b/contrib/bind-9.5.2/lib/bind/irs/lcl_nw.c new file mode 100644 index 0000000000..79b55a0c04 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/lcl_nw.c @@ -0,0 +1,373 @@ +/* + * Copyright (c) 1989, 1993, 1995 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: lcl_nw.c,v 1.4 2005/04/27 04:56:31 sra Exp $"; +/* from getgrent.c 8.2 (Berkeley) 3/21/94"; */ +/* from BSDI Id: getgrent.c,v 2.8 1996/05/28 18:15:14 bostic Exp $ */ +#endif /* LIBC_SCCS and not lint */ + +/* Imports */ + +#include "port_before.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include +#include "irs_p.h" +#include "lcl_p.h" + +#define MAXALIASES 35 +#define MAXADDRSIZE 4 + +struct pvt { + FILE * fp; + char line[BUFSIZ+1]; + struct nwent net; + char * aliases[MAXALIASES]; + char addr[MAXADDRSIZE]; + struct __res_state * res; + void (*free_res)(void *); +}; + +/* Forward */ + +static void nw_close(struct irs_nw *); +static struct nwent * nw_byname(struct irs_nw *, const char *, int); +static struct nwent * nw_byaddr(struct irs_nw *, void *, int, int); +static struct nwent * nw_next(struct irs_nw *); +static void nw_rewind(struct irs_nw *); +static void nw_minimize(struct irs_nw *); +static struct __res_state * nw_res_get(struct irs_nw *this); +static void nw_res_set(struct irs_nw *this, + struct __res_state *res, + void (*free_res)(void *)); + +static int init(struct irs_nw *this); + +/* Portability. */ + +#ifndef SEEK_SET +# define SEEK_SET 0 +#endif + +/* Public */ + +struct irs_nw * +irs_lcl_nw(struct irs_acc *this) { + struct irs_nw *nw; + struct pvt *pvt; + + UNUSED(this); + + if (!(pvt = memget(sizeof *pvt))) { + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + if (!(nw = memget(sizeof *nw))) { + memput(pvt, sizeof *pvt); + errno = ENOMEM; + return (NULL); + } + memset(nw, 0x5e, sizeof *nw); + nw->private = pvt; + nw->close = nw_close; + nw->byname = nw_byname; + nw->byaddr = nw_byaddr; + nw->next = nw_next; + nw->rewind = nw_rewind; + nw->minimize = nw_minimize; + nw->res_get = nw_res_get; + nw->res_set = nw_res_set; + return (nw); +} + +/* Methods */ + +static void +nw_close(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + nw_minimize(this); + if (pvt->res && pvt->free_res) + (*pvt->free_res)(pvt->res); + if (pvt->fp) + (void)fclose(pvt->fp); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct nwent * +nw_byaddr(struct irs_nw *this, void *net, int length, int type) { + struct nwent *p; + + if (init(this) == -1) + return(NULL); + + nw_rewind(this); + while ((p = nw_next(this)) != NULL) + if (p->n_addrtype == type && p->n_length == length) + if (bitncmp(p->n_addr, net, length) == 0) + break; + return (p); +} + +static struct nwent * +nw_byname(struct irs_nw *this, const char *name, int type) { + struct nwent *p; + char **ap; + + if (init(this) == -1) + return(NULL); + + nw_rewind(this); + while ((p = nw_next(this)) != NULL) { + if (ns_samename(p->n_name, name) == 1 && + p->n_addrtype == type) + break; + for (ap = p->n_aliases; *ap; ap++) + if ((ns_samename(*ap, name) == 1) && + (p->n_addrtype == type)) + goto found; + } + found: + return (p); +} + +static void +nw_rewind(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->fp) { + if (fseek(pvt->fp, 0L, SEEK_SET) == 0) + return; + (void)fclose(pvt->fp); + } + if (!(pvt->fp = fopen(_PATH_NETWORKS, "r"))) + return; + if (fcntl(fileno(pvt->fp), F_SETFD, 1) < 0) { + (void)fclose(pvt->fp); + pvt->fp = NULL; + } +} + +static struct nwent * +nw_next(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct nwent *ret = NULL; + char *p, *cp, **q; + char *bufp, *ndbuf, *dbuf = NULL; + int c, bufsiz, offset = 0; + + if (init(this) == -1) + return(NULL); + + if (pvt->fp == NULL) + nw_rewind(this); + if (pvt->fp == NULL) { + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + return (NULL); + } + bufp = pvt->line; + bufsiz = sizeof(pvt->line); + + again: + p = fgets(bufp + offset, bufsiz - offset, pvt->fp); + if (p == NULL) + goto cleanup; + if (!strchr(p, '\n') && !feof(pvt->fp)) { +#define GROWBUF 1024 + /* allocate space for longer line */ + if (dbuf == NULL) { + if ((ndbuf = malloc(bufsiz + GROWBUF)) != NULL) + strcpy(ndbuf, bufp); + } else + ndbuf = realloc(dbuf, bufsiz + GROWBUF); + if (ndbuf) { + dbuf = ndbuf; + bufp = dbuf; + bufsiz += GROWBUF; + offset = strlen(dbuf); + } else { + /* allocation failed; skip this long line */ + while ((c = getc(pvt->fp)) != EOF) + if (c == '\n') + break; + if (c != EOF) + ungetc(c, pvt->fp); + } + goto again; + } + + p -= offset; + offset = 0; + + if (*p == '#') + goto again; + + cp = strpbrk(p, "#\n"); + if (cp != NULL) + *cp = '\0'; + pvt->net.n_name = p; + cp = strpbrk(p, " \t"); + if (cp == NULL) + goto again; + *cp++ = '\0'; + while (*cp == ' ' || *cp == '\t') + cp++; + p = strpbrk(cp, " \t"); + if (p != NULL) + *p++ = '\0'; + pvt->net.n_length = inet_net_pton(AF_INET, cp, pvt->addr, + sizeof pvt->addr); + if (pvt->net.n_length < 0) + goto again; + pvt->net.n_addrtype = AF_INET; + pvt->net.n_addr = pvt->addr; + q = pvt->net.n_aliases = pvt->aliases; + if (p != NULL) { + cp = p; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &pvt->aliases[MAXALIASES - 1]) + *q++ = cp; + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + } + } + *q = NULL; + ret = &pvt->net; + + cleanup: + if (dbuf) + free(dbuf); + + return (ret); +} + +static void +nw_minimize(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->res) + res_nclose(pvt->res); + if (pvt->fp != NULL) { + (void)fclose(pvt->fp); + pvt->fp = NULL; + } +} + +static struct __res_state * +nw_res_get(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->res) { + struct __res_state *res; + res = (struct __res_state *)malloc(sizeof *res); + if (!res) { + errno = ENOMEM; + return (NULL); + } + memset(res, 0, sizeof *res); + nw_res_set(this, res, free); + } + + return (pvt->res); +} + +static void +nw_res_set(struct irs_nw *this, struct __res_state *res, + void (*free_res)(void *)) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->res && pvt->free_res) { + res_nclose(pvt->res); + (*pvt->free_res)(pvt->res); + } + + pvt->res = res; + pvt->free_res = free_res; +} + +static int +init(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->res && !nw_res_get(this)) + return (-1); + if (((pvt->res->options & RES_INIT) == 0U) && + res_ninit(pvt->res) == -1) + return (-1); + return (0); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/lcl_p.h b/contrib/bind-9.5.2/lib/bind/irs/lcl_p.h new file mode 100644 index 0000000000..e3f4f009cb --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/lcl_p.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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: lcl_p.h,v 1.3 2005/04/27 04:56:31 sra Exp $ + */ + +/*! \file + * \brief + * lcl_p.h - private include file for the local accessor functions. + */ + +#ifndef _LCL_P_H_INCLUDED +#define _LCL_P_H_INCLUDED + +/*% + * Object state. + */ +struct lcl_p { + struct __res_state * res; + void (*free_res) __P((void *)); +}; + +/* + * Externs. + */ + +extern struct irs_acc * irs_lcl_acc __P((const char *)); +extern struct irs_gr * irs_lcl_gr __P((struct irs_acc *)); +extern struct irs_pw * irs_lcl_pw __P((struct irs_acc *)); +extern struct irs_sv * irs_lcl_sv __P((struct irs_acc *)); +extern struct irs_pr * irs_lcl_pr __P((struct irs_acc *)); +extern struct irs_ho * irs_lcl_ho __P((struct irs_acc *)); +extern struct irs_nw * irs_lcl_nw __P((struct irs_acc *)); +extern struct irs_ng * irs_lcl_ng __P((struct irs_acc *)); + +#endif /*_LCL_P_H_INCLUDED*/ diff --git a/contrib/bind-9.5.2/lib/bind/irs/lcl_pr.c b/contrib/bind-9.5.2/lib/bind/irs/lcl_pr.c new file mode 100644 index 0000000000..622158eb17 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/lcl_pr.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 1989, 1993, 1995 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: lcl_pr.c,v 1.4 2006/03/09 23:57:56 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* extern */ + +#include "port_before.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "lcl_p.h" + +#ifndef _PATH_PROTOCOLS +#define _PATH_PROTOCOLS "/etc/protocols" +#endif +#define MAXALIASES 35 + +/* Types */ + +struct pvt { + FILE * fp; + char line[BUFSIZ+1]; + char * dbuf; + struct protoent proto; + char * proto_aliases[MAXALIASES]; +}; + +/* Forward */ + +static void pr_close(struct irs_pr *); +static struct protoent * pr_next(struct irs_pr *); +static struct protoent * pr_byname(struct irs_pr *, const char *); +static struct protoent * pr_bynumber(struct irs_pr *, int); +static void pr_rewind(struct irs_pr *); +static void pr_minimize(struct irs_pr *); + +/* Portability. */ + +#ifndef SEEK_SET +# define SEEK_SET 0 +#endif + +/* Public */ + +struct irs_pr * +irs_lcl_pr(struct irs_acc *this) { + struct irs_pr *pr; + struct pvt *pvt; + + if (!(pr = memget(sizeof *pr))) { + errno = ENOMEM; + return (NULL); + } + if (!(pvt = memget(sizeof *pvt))) { + memput(pr, sizeof *this); + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + pr->private = pvt; + pr->close = pr_close; + pr->byname = pr_byname; + pr->bynumber = pr_bynumber; + pr->next = pr_next; + pr->rewind = pr_rewind; + pr->minimize = pr_minimize; + pr->res_get = NULL; + pr->res_set = NULL; + return (pr); +} + +/* Methods */ + +static void +pr_close(struct irs_pr *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->fp) + (void) fclose(pvt->fp); + if (pvt->dbuf) + free(pvt->dbuf); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct protoent * +pr_byname(struct irs_pr *this, const char *name) { + + struct protoent *p; + char **cp; + + pr_rewind(this); + while ((p = pr_next(this))) { + if (!strcmp(p->p_name, name)) + goto found; + for (cp = p->p_aliases; *cp; cp++) + if (!strcmp(*cp, name)) + goto found; + } + found: + return (p); +} + +static struct protoent * +pr_bynumber(struct irs_pr *this, int proto) { + struct protoent *p; + + pr_rewind(this); + while ((p = pr_next(this))) + if (p->p_proto == proto) + break; + return (p); +} + +static void +pr_rewind(struct irs_pr *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->fp) { + if (fseek(pvt->fp, 0L, SEEK_SET) == 0) + return; + (void)fclose(pvt->fp); + } + if (!(pvt->fp = fopen(_PATH_PROTOCOLS, "r" ))) + return; + if (fcntl(fileno(pvt->fp), F_SETFD, 1) < 0) { + (void)fclose(pvt->fp); + pvt->fp = NULL; + } +} + +static struct protoent * +pr_next(struct irs_pr *this) { + struct pvt *pvt = (struct pvt *)this->private; + char *p, *cp, **q; + char *bufp, *ndbuf, *dbuf = NULL; + int c, bufsiz, offset; + + if (!pvt->fp) + pr_rewind(this); + if (!pvt->fp) + return (NULL); + if (pvt->dbuf) { + free(pvt->dbuf); + pvt->dbuf = NULL; + } + bufp = pvt->line; + bufsiz = BUFSIZ; + offset = 0; + again: + if ((p = fgets(bufp + offset, bufsiz - offset, pvt->fp)) == NULL) { + if (dbuf) + free(dbuf); + return (NULL); + } + if (!strchr(p, '\n') && !feof(pvt->fp)) { +#define GROWBUF 1024 + /* allocate space for longer line */ + if (dbuf == NULL) { + if ((ndbuf = malloc(bufsiz + GROWBUF)) != NULL) + strcpy(ndbuf, bufp); + } else + ndbuf = realloc(dbuf, bufsiz + GROWBUF); + if (ndbuf) { + dbuf = ndbuf; + bufp = dbuf; + bufsiz += GROWBUF; + offset = strlen(dbuf); + } else { + /* allocation failed; skip this long line */ + while ((c = getc(pvt->fp)) != EOF) + if (c == '\n') + break; + if (c != EOF) + ungetc(c, pvt->fp); + } + goto again; + } + + p -= offset; + offset = 0; + + if (*p == '#') + goto again; + cp = strpbrk(p, "#\n"); + if (cp != NULL) + *cp = '\0'; + pvt->proto.p_name = p; + cp = strpbrk(p, " \t"); + if (cp == NULL) + goto again; + *cp++ = '\0'; + while (*cp == ' ' || *cp == '\t') + cp++; + p = strpbrk(cp, " \t"); + if (p != NULL) + *p++ = '\0'; + pvt->proto.p_proto = atoi(cp); + q = pvt->proto.p_aliases = pvt->proto_aliases; + if (p != NULL) { + cp = p; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &pvt->proto_aliases[MAXALIASES - 1]) + *q++ = cp; + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + } + } + *q = NULL; + pvt->dbuf = dbuf; + return (&pvt->proto); +} + +static void +pr_minimize(struct irs_pr *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->fp != NULL) { + (void)fclose(pvt->fp); + pvt->fp = NULL; + } +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/lcl_pw.c b/contrib/bind-9.5.2/lib/bind/irs/lcl_pw.c new file mode 100644 index 0000000000..ffca5541bb --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/lcl_pw.c @@ -0,0 +1,309 @@ +/* + * Copyright (c) 1989, 1993, 1995 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: lcl_pw.c,v 1.3 2005/04/27 04:56:31 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* Extern */ + +#include "port_before.h" + +#ifndef WANT_IRS_PW +static int __bind_irs_pw_unneeded; +#else + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "lcl_p.h" + +/*! \file + * \brief + * The lookup techniques and data extraction code here must be kept + * in sync with that in `pwd_mkdb'. + */ + + +/* Types */ + +struct pvt { + struct passwd passwd; /*%< password structure */ + DB *pw_db; /*%< password database */ + int pw_keynum; /*%< key counter */ + int warned; + u_int max; + char * line; +}; + +/* Forward */ + +static void pw_close(struct irs_pw *); +static struct passwd * pw_next(struct irs_pw *); +static struct passwd * pw_byname(struct irs_pw *, const char *); +static struct passwd * pw_byuid(struct irs_pw *, uid_t); +static void pw_rewind(struct irs_pw *); +static void pw_minimize(struct irs_pw *); + +static int initdb(struct pvt *); +static int hashpw(struct irs_pw *, DBT *); + +/* Public */ +struct irs_pw * +irs_lcl_pw(struct irs_acc *this) { + struct irs_pw *pw; + struct pvt *pvt; + + UNUSED(this); + + if (!(pw = memget(sizeof *pw))) { + errno = ENOMEM; + return (NULL); + } + memset(pw, 0x5e, sizeof *pw); + if (!(pvt = memget(sizeof *pvt))) { + free(pw); + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + pw->private = pvt; + pw->close = pw_close; + pw->next = pw_next; + pw->byname = pw_byname; + pw->byuid = pw_byuid; + pw->rewind = pw_rewind; + pw->minimize = pw_minimize; + pw->res_get = NULL; + pw->res_set = NULL; + return (pw); +} + +/* Methods */ + +static void +pw_close(struct irs_pw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->pw_db) { + (void)(pvt->pw_db->close)(pvt->pw_db); + pvt->pw_db = NULL; + } + if (pvt->line) + memput(pvt->line, pvt->max); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct passwd * +pw_next(struct irs_pw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + DBT key; + char bf[sizeof(pvt->pw_keynum) + 1]; + + if (!initdb(pvt)) + return (NULL); + + ++pvt->pw_keynum; + bf[0] = _PW_KEYBYNUM; + memcpy(bf + 1, (char *)&pvt->pw_keynum, sizeof(pvt->pw_keynum)); + key.data = (u_char *)bf; + key.size = sizeof(pvt->pw_keynum) + 1; + return (hashpw(this, &key) ? &pvt->passwd : NULL); +} + +static struct passwd * +pw_byname(struct irs_pw *this, const char *name) { + struct pvt *pvt = (struct pvt *)this->private; + DBT key; + int len, rval; + char bf[UT_NAMESIZE + 1]; + + if (!initdb(pvt)) + return (NULL); + + bf[0] = _PW_KEYBYNAME; + len = strlen(name); + memcpy(bf + 1, name, MIN(len, UT_NAMESIZE)); + key.data = (u_char *)bf; + key.size = len + 1; + rval = hashpw(this, &key); + + return (rval ? &pvt->passwd : NULL); +} + + +static struct passwd * +pw_byuid(struct irs_pw *this, uid_t uid) { + struct pvt *pvt = (struct pvt *)this->private; + DBT key; + int keyuid, rval; + char bf[sizeof(keyuid) + 1]; + + if (!initdb(pvt)) + return (NULL); + + bf[0] = _PW_KEYBYUID; + keyuid = uid; + memcpy(bf + 1, &keyuid, sizeof(keyuid)); + key.data = (u_char *)bf; + key.size = sizeof(keyuid) + 1; + rval = hashpw(this, &key); + + return (rval ? &pvt->passwd : NULL); +} + +static void +pw_rewind(struct irs_pw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + pvt->pw_keynum = 0; +} + +static void +pw_minimize(struct irs_pw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->pw_db != NULL) { + (void) (*pvt->pw_db->close)(pvt->pw_db); + pvt->pw_db = NULL; + } +} + +/* Private. */ + +static int +initdb(struct pvt *pvt) { + const char *p; + + if (pvt->pw_db) { + if (lseek((*pvt->pw_db->fd)(pvt->pw_db), 0L, SEEK_CUR) >= 0L) + return (1); + else + (void) (*pvt->pw_db->close)(pvt->pw_db); + } + pvt->pw_db = dbopen((p = _PATH_SMP_DB), O_RDONLY, 0, DB_HASH, NULL); + if (!pvt->pw_db) + pvt->pw_db = dbopen((p =_PATH_MP_DB), O_RDONLY, + 0, DB_HASH, NULL); + if (pvt->pw_db) + return (1); + if (!pvt->warned) { + syslog(LOG_ERR, "%s: %m", p); + pvt->warned++; + } + return (0); +} + +static int +hashpw(struct irs_pw *this, DBT *key) { + struct pvt *pvt = (struct pvt *)this->private; + char *p, *t, *l; + DBT data; + + if ((pvt->pw_db->get)(pvt->pw_db, key, &data, 0)) + return (0); + p = (char *)data.data; + if (data.size > pvt->max) { + size_t newlen = pvt->max + 1024; + char *p = memget(newlen); + if (p == NULL) { + return (0); + } + if (pvt->line != NULL) { + memcpy(p, pvt->line, pvt->max); + memput(pvt->line, pvt->max); + } + pvt->max = newlen; + pvt->line = p; + } + + /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */ + t = pvt->line; + l = pvt->line + pvt->max; +#define EXPAND(e) if ((e = t) == NULL) return (0); else \ + do if (t >= l) return (0); while ((*t++ = *p++) != '\0') +#define SCALAR(v) if (t + sizeof v >= l) return (0); else \ + (memmove(&(v), p, sizeof v), p += sizeof v) + EXPAND(pvt->passwd.pw_name); + EXPAND(pvt->passwd.pw_passwd); + SCALAR(pvt->passwd.pw_uid); + SCALAR(pvt->passwd.pw_gid); + SCALAR(pvt->passwd.pw_change); + EXPAND(pvt->passwd.pw_class); + EXPAND(pvt->passwd.pw_gecos); + EXPAND(pvt->passwd.pw_dir); + EXPAND(pvt->passwd.pw_shell); + SCALAR(pvt->passwd.pw_expire); + return (1); +} + +#endif /* WANT_IRS_PW */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/lcl_sv.c b/contrib/bind-9.5.2/lib/bind/irs/lcl_sv.c new file mode 100644 index 0000000000..8d0049bb46 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/lcl_sv.c @@ -0,0 +1,432 @@ +/* + * Copyright (c) 1989, 1993, 1995 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: lcl_sv.c,v 1.4 2005/04/27 04:56:31 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* extern */ + +#include "port_before.h" + +#include +#include +#include +#include +#include + +#ifdef IRS_LCL_SV_DB +#include +#endif +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "lcl_p.h" + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +/* Types */ + +struct pvt { +#ifdef IRS_LCL_SV_DB + DB * dbh; + int dbf; +#endif + struct lcl_sv sv; +}; + +/* Forward */ + +static void sv_close(struct irs_sv*); +static struct servent * sv_next(struct irs_sv *); +static struct servent * sv_byname(struct irs_sv *, const char *, + const char *); +static struct servent * sv_byport(struct irs_sv *, int, const char *); +static void sv_rewind(struct irs_sv *); +static void sv_minimize(struct irs_sv *); +/*global*/ struct servent * irs_lclsv_fnxt(struct lcl_sv *); +#ifdef IRS_LCL_SV_DB +static struct servent * sv_db_rec(struct lcl_sv *, DBT *, DBT *); +#endif + +/* Portability */ + +#ifndef SEEK_SET +# define SEEK_SET 0 +#endif + +/* Public */ + +struct irs_sv * +irs_lcl_sv(struct irs_acc *this) { + struct irs_sv *sv; + struct pvt *pvt; + + UNUSED(this); + + if ((sv = memget(sizeof *sv)) == NULL) { + errno = ENOMEM; + return (NULL); + } + memset(sv, 0x5e, sizeof *sv); + if ((pvt = memget(sizeof *pvt)) == NULL) { + memput(sv, sizeof *sv); + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + sv->private = pvt; + sv->close = sv_close; + sv->next = sv_next; + sv->byname = sv_byname; + sv->byport = sv_byport; + sv->rewind = sv_rewind; + sv->minimize = sv_minimize; + sv->res_get = NULL; + sv->res_set = NULL; +#ifdef IRS_LCL_SV_DB + pvt->dbf = R_FIRST; +#endif + return (sv); +} + +/* Methods */ + +static void +sv_close(struct irs_sv *this) { + struct pvt *pvt = (struct pvt *)this->private; + +#ifdef IRS_LCL_SV_DB + if (pvt->dbh != NULL) + (*pvt->dbh->close)(pvt->dbh); +#endif + if (pvt->sv.fp) + fclose(pvt->sv.fp); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct servent * +sv_byname(struct irs_sv *this, const char *name, const char *proto) { +#ifdef IRS_LCL_SV_DB + struct pvt *pvt = (struct pvt *)this->private; +#endif + struct servent *p; + char **cp; + + sv_rewind(this); +#ifdef IRS_LCL_SV_DB + if (pvt->dbh != NULL) { + DBT key, data; + + /* Note that (sizeof "/") == 2. */ + if ((strlen(name) + sizeof "/" + proto ? strlen(proto) : 0) + > sizeof pvt->sv.line) + goto try_local; + key.data = pvt->sv.line; + key.size = SPRINTF((pvt->sv.line, "%s/%s", name, + proto ? proto : "")) + 1; + if (proto != NULL) { + if ((*pvt->dbh->get)(pvt->dbh, &key, &data, 0) != 0) + return (NULL); + } else if ((*pvt->dbh->seq)(pvt->dbh, &key, &data, R_CURSOR) + != 0) + return (NULL); + return (sv_db_rec(&pvt->sv, &key, &data)); + } + try_local: +#endif + + while ((p = sv_next(this))) { + if (strcmp(name, p->s_name) == 0) + goto gotname; + for (cp = p->s_aliases; *cp; cp++) + if (strcmp(name, *cp) == 0) + goto gotname; + continue; + gotname: + if (proto == NULL || strcmp(p->s_proto, proto) == 0) + break; + } + return (p); +} + +static struct servent * +sv_byport(struct irs_sv *this, int port, const char *proto) { +#ifdef IRS_LCL_SV_DB + struct pvt *pvt = (struct pvt *)this->private; +#endif + struct servent *p; + + sv_rewind(this); +#ifdef IRS_LCL_SV_DB + if (pvt->dbh != NULL) { + DBT key, data; + u_short *ports; + + ports = (u_short *)pvt->sv.line; + ports[0] = 0; + ports[1] = port; + key.data = ports; + key.size = sizeof(u_short) * 2; + if (proto && *proto) { + strncpy((char *)ports + key.size, proto, + BUFSIZ - key.size); + key.size += strlen((char *)ports + key.size) + 1; + if ((*pvt->dbh->get)(pvt->dbh, &key, &data, 0) != 0) + return (NULL); + } else { + if ((*pvt->dbh->seq)(pvt->dbh, &key, &data, R_CURSOR) + != 0) + return (NULL); + } + return (sv_db_rec(&pvt->sv, &key, &data)); + } +#endif + while ((p = sv_next(this))) { + if (p->s_port != port) + continue; + if (proto == NULL || strcmp(p->s_proto, proto) == 0) + break; + } + return (p); +} + +static void +sv_rewind(struct irs_sv *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->sv.fp) { + if (fseek(pvt->sv.fp, 0L, SEEK_SET) == 0) + return; + (void)fclose(pvt->sv.fp); + pvt->sv.fp = NULL; + } +#ifdef IRS_LCL_SV_DB + pvt->dbf = R_FIRST; + if (pvt->dbh != NULL) + return; + pvt->dbh = dbopen(_PATH_SERVICES_DB, O_RDONLY,O_RDONLY,DB_BTREE, NULL); + if (pvt->dbh != NULL) { + if (fcntl((*pvt->dbh->fd)(pvt->dbh), F_SETFD, 1) < 0) { + (*pvt->dbh->close)(pvt->dbh); + pvt->dbh = NULL; + } + return; + } +#endif + if ((pvt->sv.fp = fopen(_PATH_SERVICES, "r")) == NULL) + return; + if (fcntl(fileno(pvt->sv.fp), F_SETFD, 1) < 0) { + (void)fclose(pvt->sv.fp); + pvt->sv.fp = NULL; + } +} + +static struct servent * +sv_next(struct irs_sv *this) { + struct pvt *pvt = (struct pvt *)this->private; + +#ifdef IRS_LCL_SV_DB + if (pvt->dbh == NULL && pvt->sv.fp == NULL) +#else + if (pvt->sv.fp == NULL) +#endif + sv_rewind(this); + +#ifdef IRS_LCL_SV_DB + if (pvt->dbh != NULL) { + DBT key, data; + + while ((*pvt->dbh->seq)(pvt->dbh, &key, &data, pvt->dbf) == 0){ + pvt->dbf = R_NEXT; + if (((char *)key.data)[0]) + continue; + return (sv_db_rec(&pvt->sv, &key, &data)); + } + } +#endif + + if (pvt->sv.fp == NULL) + return (NULL); + return (irs_lclsv_fnxt(&pvt->sv)); +} + +static void +sv_minimize(struct irs_sv *this) { + struct pvt *pvt = (struct pvt *)this->private; + +#ifdef IRS_LCL_SV_DB + if (pvt->dbh != NULL) { + (*pvt->dbh->close)(pvt->dbh); + pvt->dbh = NULL; + } +#endif + if (pvt->sv.fp != NULL) { + (void)fclose(pvt->sv.fp); + pvt->sv.fp = NULL; + } +} + +/* Quasipublic. */ + +struct servent * +irs_lclsv_fnxt(struct lcl_sv *sv) { + char *p, *cp, **q; + + again: + if ((p = fgets(sv->line, BUFSIZ, sv->fp)) == NULL) + return (NULL); + if (*p == '#') + goto again; + sv->serv.s_name = p; + while (*p && *p != '\n' && *p != ' ' && *p != '\t' && *p != '#') + ++p; + if (*p == '\0' || *p == '#' || *p == '\n') + goto again; + *p++ = '\0'; + while (*p == ' ' || *p == '\t') + p++; + if (*p == '\0' || *p == '#' || *p == '\n') + goto again; + sv->serv.s_port = htons((u_short)strtol(p, &cp, 10)); + if (cp == p || (*cp != '/' && *cp != ',')) + goto again; + p = cp + 1; + sv->serv.s_proto = p; + + q = sv->serv.s_aliases = sv->serv_aliases; + + while (*p && *p != '\n' && *p != ' ' && *p != '\t' && *p != '#') + ++p; + + while (*p == ' ' || *p == '\t') { + *p++ = '\0'; + while (*p == ' ' || *p == '\t') + ++p; + if (*p == '\0' || *p == '#' || *p == '\n') + break; + if (q < &sv->serv_aliases[IRS_SV_MAXALIASES - 1]) + *q++ = p; + while (*p && *p != '\n' && *p != ' ' && *p != '\t' && *p != '#') + ++p; + } + + *p = '\0'; + *q = NULL; + return (&sv->serv); +} + +/* Private. */ + +#ifdef IRS_LCL_SV_DB +static struct servent * +sv_db_rec(struct lcl_sv *sv, DBT *key, DBT *data) { + char *p, **q; + int n; + + p = data->data; + p[data->size - 1] = '\0'; /*%< should be, but we depend on it */ + if (((char *)key->data)[0] == '\0') { + if (key->size < sizeof(u_short)*2 || data->size < 2) + return (NULL); + sv->serv.s_port = ((u_short *)key->data)[1]; + n = strlen(p) + 1; + if ((size_t)n > sizeof(sv->line)) { + n = sizeof(sv->line); + } + memcpy(sv->line, p, n); + sv->serv.s_name = sv->line; + if ((sv->serv.s_proto = strchr(sv->line, '/')) != NULL) + *(sv->serv.s_proto)++ = '\0'; + p += n; + data->size -= n; + } else { + if (data->size < sizeof(u_short) + 1) + return (NULL); + if (key->size > sizeof(sv->line)) + key->size = sizeof(sv->line); + ((char *)key->data)[key->size - 1] = '\0'; + memcpy(sv->line, key->data, key->size); + sv->serv.s_name = sv->line; + if ((sv->serv.s_proto = strchr(sv->line, '/')) != NULL) + *(sv->serv.s_proto)++ = '\0'; + sv->serv.s_port = *(u_short *)data->data; + p += sizeof(u_short); + data->size -= sizeof(u_short); + } + q = sv->serv.s_aliases = sv->serv_aliases; + while (data->size > 0 && q < &sv->serv_aliases[IRS_SV_MAXALIASES - 1]) { + + *q++ = p; + n = strlen(p) + 1; + data->size -= n; + p += n; + } + *q = NULL; + return (&sv->serv); +} +#endif + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/nis.c b/contrib/bind-9.5.2/lib/bind/irs/nis.c new file mode 100644 index 0000000000..9abc47403a --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/nis.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: nis.c,v 1.3 2005/04/27 04:56:32 sra Exp $"; +#endif + +/* Imports */ + +#include "port_before.h" + +#ifdef WANT_IRS_NIS + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#ifdef T_NULL +#undef T_NULL /* Silence re-definition warning of T_NULL. */ +#endif +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "hesiod.h" +#include "nis_p.h" + +/* Forward */ + +static void nis_close(struct irs_acc *); +static struct __res_state * nis_res_get(struct irs_acc *); +static void nis_res_set(struct irs_acc *, struct __res_state *, + void (*)(void *)); + +/* Public */ + +struct irs_acc * +irs_nis_acc(const char *options) { + struct nis_p *nis; + struct irs_acc *acc; + char *domain; + + UNUSED(options); + + if (yp_get_default_domain(&domain) != 0) + return (NULL); + if (!(nis = memget(sizeof *nis))) { + errno = ENOMEM; + return (NULL); + } + memset(nis, 0, sizeof *nis); + if (!(acc = memget(sizeof *acc))) { + memput(nis, sizeof *nis); + errno = ENOMEM; + return (NULL); + } + memset(acc, 0x5e, sizeof *acc); + acc->private = nis; + nis->domain = strdup(domain); +#ifdef WANT_IRS_GR + acc->gr_map = irs_nis_gr; +#else + acc->gr_map = NULL; +#endif +#ifdef WANT_IRS_PW + acc->pw_map = irs_nis_pw; +#else + acc->pw_map = NULL; +#endif + acc->sv_map = irs_nis_sv; + acc->pr_map = irs_nis_pr; + acc->ho_map = irs_nis_ho; + acc->nw_map = irs_nis_nw; + acc->ng_map = irs_nis_ng; + acc->res_get = nis_res_get; + acc->res_set = nis_res_set; + acc->close = nis_close; + return (acc); +} + +/* Methods */ + +static struct __res_state * +nis_res_get(struct irs_acc *this) { + struct nis_p *nis = (struct nis_p *)this->private; + + if (nis->res == NULL) { + struct __res_state *res; + res = (struct __res_state *)malloc(sizeof *res); + if (res == NULL) + return (NULL); + memset(res, 0, sizeof *res); + nis_res_set(this, res, free); + } + + if ((nis->res->options & RES_INIT) == 0 && + res_ninit(nis->res) < 0) + return (NULL); + + return (nis->res); +} + +static void +nis_res_set(struct irs_acc *this, struct __res_state *res, + void (*free_res)(void *)) { + struct nis_p *nis = (struct nis_p *)this->private; + + if (nis->res && nis->free_res) { + res_nclose(nis->res); + (*nis->free_res)(nis->res); + } + + nis->res = res; + nis->free_res = free_res; +} + +static void +nis_close(struct irs_acc *this) { + struct nis_p *nis = (struct nis_p *)this->private; + + if (nis->res && nis->free_res) + (*nis->free_res)(nis->res); + free(nis->domain); + memput(nis, sizeof *nis); + memput(this, sizeof *this); +} + +#endif /*WANT_IRS_NIS*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/nis_gr.c b/contrib/bind-9.5.2/lib/bind/irs/nis_gr.c new file mode 100644 index 0000000000..c7c8d83043 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/nis_gr.c @@ -0,0 +1,354 @@ +/* + * Copyright (c) 1989, 1993, 1995 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: nis_gr.c,v 1.4 2005/04/27 04:56:32 sra Exp $"; +/* from getgrent.c 8.2 (Berkeley) 3/21/94"; */ +/* from BSDI Id: getgrent.c,v 2.8 1996/05/28 18:15:14 bostic Exp $ */ +#endif /* LIBC_SCCS and not lint */ + +/* Imports */ + +#include "port_before.h" + +#if !defined(WANT_IRS_GR) || !defined(WANT_IRS_NIS) +static int __bind_irs_gr_unneeded; +#else + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "nis_p.h" + +/* Definitions */ + +struct pvt { + int needrewind; + char * nis_domain; + char * curkey_data; + int curkey_len; + char * curval_data; + int curval_len; + /*%< + * Need space to store the entries read from the group file. + * The members list also needs space per member, and the + * strings making up the user names must be allocated + * somewhere. Rather than doing lots of small allocations, + * we keep one buffer and resize it as needed. + */ + struct group group; + size_t nmemb; /*%< Malloc'd max index of gr_mem[]. */ + char * membuf; + size_t membufsize; +}; + +enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 }; + +static /*const*/ char group_bygid[] = "group.bygid"; +static /*const*/ char group_byname[] = "group.byname"; + +/* Forward */ + +static void gr_close(struct irs_gr *); +static struct group * gr_next(struct irs_gr *); +static struct group * gr_byname(struct irs_gr *, const char *); +static struct group * gr_bygid(struct irs_gr *, gid_t); +static void gr_rewind(struct irs_gr *); +static void gr_minimize(struct irs_gr *); + +static struct group * makegroupent(struct irs_gr *); +static void nisfree(struct pvt *, enum do_what); + +/* Public */ + +struct irs_gr * +irs_nis_gr(struct irs_acc *this) { + struct irs_gr *gr; + struct pvt *pvt; + + if (!(gr = memget(sizeof *gr))) { + errno = ENOMEM; + return (NULL); + } + memset(gr, 0x5e, sizeof *gr); + if (!(pvt = memget(sizeof *pvt))) { + memput(gr, sizeof *gr); + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + pvt->needrewind = 1; + pvt->nis_domain = ((struct nis_p *)this->private)->domain; + gr->private = pvt; + gr->close = gr_close; + gr->next = gr_next; + gr->byname = gr_byname; + gr->bygid = gr_bygid; + gr->rewind = gr_rewind; + gr->list = make_group_list; + gr->minimize = gr_minimize; + gr->res_get = NULL; + gr->res_set = NULL; + return (gr); +} + +/* Methods */ + +static void +gr_close(struct irs_gr *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->group.gr_mem) + free(pvt->group.gr_mem); + if (pvt->membuf) + free(pvt->membuf); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct group * +gr_next(struct irs_gr *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct group *rval; + int r; + + do { + if (pvt->needrewind) { + nisfree(pvt, do_all); + r = yp_first(pvt->nis_domain, group_byname, + &pvt->curkey_data, &pvt->curkey_len, + &pvt->curval_data, &pvt->curval_len); + pvt->needrewind = 0; + } else { + char *newkey_data; + int newkey_len; + + nisfree(pvt, do_val); + r = yp_next(pvt->nis_domain, group_byname, + pvt->curkey_data, pvt->curkey_len, + &newkey_data, &newkey_len, + &pvt->curval_data, &pvt->curval_len); + nisfree(pvt, do_key); + pvt->curkey_data = newkey_data; + pvt->curkey_len = newkey_len; + } + if (r != 0) { + errno = ENOENT; + return (NULL); + } + rval = makegroupent(this); + } while (rval == NULL); + return (rval); +} + +static struct group * +gr_byname(struct irs_gr *this, const char *name) { + struct pvt *pvt = (struct pvt *)this->private; + int r; + + nisfree(pvt, do_val); + r = yp_match(pvt->nis_domain, group_byname, name, strlen(name), + &pvt->curval_data, &pvt->curval_len); + if (r != 0) { + errno = ENOENT; + return (NULL); + } + return (makegroupent(this)); +} + +static struct group * +gr_bygid(struct irs_gr *this, gid_t gid) { + struct pvt *pvt = (struct pvt *)this->private; + char tmp[sizeof "4294967295"]; + int r; + + nisfree(pvt, do_val); + (void) sprintf(tmp, "%u", (unsigned int)gid); + r = yp_match(pvt->nis_domain, group_bygid, tmp, strlen(tmp), + &pvt->curval_data, &pvt->curval_len); + if (r != 0) { + errno = ENOENT; + return (NULL); + } + return (makegroupent(this)); +} + +static void +gr_rewind(struct irs_gr *this) { + struct pvt *pvt = (struct pvt *)this->private; + + pvt->needrewind = 1; +} + +static void +gr_minimize(struct irs_gr *this) { + UNUSED(this); + /* NOOP */ +} + +/* Private */ + +static struct group * +makegroupent(struct irs_gr *this) { + struct pvt *pvt = (struct pvt *)this->private; + unsigned int num_members = 0; + char *cp, **new; + u_long t; + + if (pvt->group.gr_mem) { + free(pvt->group.gr_mem); + pvt->group.gr_mem = NULL; + pvt->nmemb = 0; + } + if (pvt->membuf) + free(pvt->membuf); + pvt->membuf = pvt->curval_data; + pvt->curval_data = NULL; + + cp = pvt->membuf; + pvt->group.gr_name = cp; + if (!(cp = strchr(cp, ':'))) + goto cleanup; + *cp++ = '\0'; + + pvt->group.gr_passwd = cp; + if (!(cp = strchr(cp, ':'))) + goto cleanup; + *cp++ = '\0'; + + errno = 0; + t = strtoul(cp, NULL, 10); + if (errno == ERANGE) + goto cleanup; + pvt->group.gr_gid = (gid_t) t; + if (!(cp = strchr(cp, ':'))) + goto cleanup; + cp++; + + if (*cp && cp[strlen(cp)-1] == '\n') + cp[strlen(cp)-1] = '\0'; + + /* + * Parse the members out. + */ + while (*cp) { + if (num_members+1 >= pvt->nmemb || pvt->group.gr_mem == NULL) { + pvt->nmemb += 10; + new = realloc(pvt->group.gr_mem, + pvt->nmemb * sizeof(char *)); + if (new == NULL) + goto cleanup; + pvt->group.gr_mem = new; + } + pvt->group.gr_mem[num_members++] = cp; + if (!(cp = strchr(cp, ','))) + break; + *cp++ = '\0'; + } + if (pvt->group.gr_mem == NULL) { + pvt->group.gr_mem = malloc(sizeof(char*)); + if (!pvt->group.gr_mem) + goto cleanup; + pvt->nmemb = 1; + } + pvt->group.gr_mem[num_members] = NULL; + + return (&pvt->group); + + cleanup: + if (pvt->group.gr_mem) { + free(pvt->group.gr_mem); + pvt->group.gr_mem = NULL; + pvt->nmemb = 0; + } + if (pvt->membuf) { + free(pvt->membuf); + pvt->membuf = NULL; + } + return (NULL); +} + +static void +nisfree(struct pvt *pvt, enum do_what do_what) { + if ((do_what & do_key) && pvt->curkey_data) { + free(pvt->curkey_data); + pvt->curkey_data = NULL; + } + if ((do_what & do_val) && pvt->curval_data) { + free(pvt->curval_data); + pvt->curval_data = NULL; + } +} + +#endif /* WANT_IRS_GR && WANT_IRS_NIS */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/nis_ho.c b/contrib/bind-9.5.2/lib/bind/irs/nis_ho.c new file mode 100644 index 0000000000..0799613f49 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/nis_ho.c @@ -0,0 +1,535 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: nis_ho.c,v 1.5 2005/04/27 04:56:32 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* Imports */ + +#include "port_before.h" + +#ifndef WANT_IRS_NIS +static int __bind_irs_nis_unneeded; +#else + +#include +#include +#include +#include +#include +#include +#ifdef T_NULL +#undef T_NULL /* Silence re-definition warning of T_NULL. */ +#endif +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "nis_p.h" + +/* Definitions */ + +#define MAXALIASES 35 +#define MAXADDRS 35 + +#if PACKETSZ > 1024 +#define MAXPACKET PACKETSZ +#else +#define MAXPACKET 1024 +#endif + +struct pvt { + int needrewind; + char * nis_domain; + char * curkey_data; + int curkey_len; + char * curval_data; + int curval_len; + struct hostent host; + char * h_addr_ptrs[MAXADDRS + 1]; + char * host_aliases[MAXALIASES + 1]; + char hostbuf[8*1024]; + u_char host_addr[16]; /*%< IPv4 or IPv6 */ + struct __res_state *res; + void (*free_res)(void *); +}; + +enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 }; + +static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff }; +static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 }; +static /*const*/ char hosts_byname[] = "hosts.byname"; +static /*const*/ char hosts_byaddr[] = "hosts.byaddr"; +static /*const*/ char ipnode_byname[] = "ipnode.byname"; +static /*const*/ char ipnode_byaddr[] = "ipnode.byaddr"; +static /*const*/ char yp_multi[] = "YP_MULTI_"; + +/* Forwards */ + +static void ho_close(struct irs_ho *this); +static struct hostent * ho_byname(struct irs_ho *this, const char *name); +static struct hostent * ho_byname2(struct irs_ho *this, const char *name, + int af); +static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr, + int len, int af); +static struct hostent * ho_next(struct irs_ho *this); +static void ho_rewind(struct irs_ho *this); +static void ho_minimize(struct irs_ho *this); +static struct __res_state * ho_res_get(struct irs_ho *this); +static void ho_res_set(struct irs_ho *this, + struct __res_state *res, + void (*free_res)(void *)); +static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name, + const struct addrinfo *pai); + +static struct hostent * makehostent(struct irs_ho *this); +static void nisfree(struct pvt *, enum do_what); +static int init(struct irs_ho *this); + +/* Public */ + +struct irs_ho * +irs_nis_ho(struct irs_acc *this) { + struct irs_ho *ho; + struct pvt *pvt; + + if (!(pvt = memget(sizeof *pvt))) { + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + if (!(ho = memget(sizeof *ho))) { + memput(pvt, sizeof *pvt); + errno = ENOMEM; + return (NULL); + } + memset(ho, 0x5e, sizeof *ho); + pvt->needrewind = 1; + pvt->nis_domain = ((struct nis_p *)this->private)->domain; + ho->private = pvt; + ho->close = ho_close; + ho->byname = ho_byname; + ho->byname2 = ho_byname2; + ho->byaddr = ho_byaddr; + ho->next = ho_next; + ho->rewind = ho_rewind; + ho->minimize = ho_minimize; + ho->res_set = ho_res_set; + ho->res_get = ho_res_get; + ho->addrinfo = ho_addrinfo; + return (ho); +} + +/* Methods */ + +static void +ho_close(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + + ho_minimize(this); + nisfree(pvt, do_all); + if (pvt->res && pvt->free_res) + (*pvt->free_res)(pvt->res); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct hostent * +ho_byname(struct irs_ho *this, const char *name) { + struct pvt *pvt = (struct pvt *)this->private; + struct hostent *hp; + + if (init(this) == -1) + return (NULL); + + if (pvt->res->options & RES_USE_INET6) { + hp = ho_byname2(this, name, AF_INET6); + if (hp) + return (hp); + } + return (ho_byname2(this, name, AF_INET)); +} + +static struct hostent * +ho_byname2(struct irs_ho *this, const char *name, int af) { + struct pvt *pvt = (struct pvt *)this->private; + int r; + char *tmp; + + UNUSED(af); + + if (init(this) == -1) + return (NULL); + + nisfree(pvt, do_val); + + strcpy(pvt->hostbuf, yp_multi); + strncat(pvt->hostbuf, name, sizeof(pvt->hostbuf) - sizeof(yp_multi)); + pvt->hostbuf[sizeof(pvt->hostbuf) - 1] = '\0'; + for (r = sizeof(yp_multi) - 1; pvt->hostbuf[r] != '\0'; r++) + if (isupper((unsigned char)pvt->hostbuf[r])) + tolower(pvt->hostbuf[r]); + + tmp = pvt->hostbuf; + r = yp_match(pvt->nis_domain, ipnode_byname, tmp, + strlen(tmp), &pvt->curval_data, &pvt->curval_len); + if (r != 0) { + tmp = pvt->hostbuf + sizeof(yp_multi) - 1; + r = yp_match(pvt->nis_domain, ipnode_byname, tmp, + strlen(tmp), &pvt->curval_data, &pvt->curval_len); + } + if (r != 0) { + tmp = pvt->hostbuf; + r = yp_match(pvt->nis_domain, hosts_byname, tmp, + strlen(tmp), &pvt->curval_data, &pvt->curval_len); + } + if (r != 0) { + tmp = pvt->hostbuf + sizeof(yp_multi) - 1; + r = yp_match(pvt->nis_domain, hosts_byname, tmp, + strlen(tmp), &pvt->curval_data, &pvt->curval_len); + } + if (r != 0) { + RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); + return (NULL); + } + return (makehostent(this)); +} + +static struct hostent * +ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) { + struct pvt *pvt = (struct pvt *)this->private; + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; + const u_char *uaddr = addr; + int r; + + if (init(this) == -1) + return (NULL); + + if (af == AF_INET6 && len == IN6ADDRSZ && + (!memcmp(uaddr, mapped, sizeof mapped) || + !memcmp(uaddr, tunnelled, sizeof tunnelled))) { + /* Unmap. */ + addr = (const u_char *)addr + sizeof mapped; + uaddr += sizeof mapped; + af = AF_INET; + len = INADDRSZ; + } + if (inet_ntop(af, uaddr, tmp, sizeof tmp) == NULL) { + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + return (NULL); + } + nisfree(pvt, do_val); + r = yp_match(pvt->nis_domain, ipnode_byaddr, tmp, strlen(tmp), + &pvt->curval_data, &pvt->curval_len); + if (r != 0) + r = yp_match(pvt->nis_domain, hosts_byaddr, tmp, strlen(tmp), + &pvt->curval_data, &pvt->curval_len); + if (r != 0) { + RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); + return (NULL); + } + return (makehostent(this)); +} + +static struct hostent * +ho_next(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct hostent *rval; + int r; + + if (init(this) == -1) + return (NULL); + + do { + if (pvt->needrewind) { + nisfree(pvt, do_all); + r = yp_first(pvt->nis_domain, hosts_byaddr, + &pvt->curkey_data, &pvt->curkey_len, + &pvt->curval_data, &pvt->curval_len); + pvt->needrewind = 0; + } else { + char *newkey_data; + int newkey_len; + + nisfree(pvt, do_val); + r = yp_next(pvt->nis_domain, hosts_byaddr, + pvt->curkey_data, pvt->curkey_len, + &newkey_data, &newkey_len, + &pvt->curval_data, &pvt->curval_len); + nisfree(pvt, do_key); + pvt->curkey_data = newkey_data; + pvt->curkey_len = newkey_len; + } + if (r != 0) { + RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); + return (NULL); + } + rval = makehostent(this); + } while (rval == NULL); + return (rval); +} + +static void +ho_rewind(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + + pvt->needrewind = 1; +} + +static void +ho_minimize(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->res) + res_nclose(pvt->res); +} + +static struct __res_state * +ho_res_get(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->res) { + struct __res_state *res; + res = (struct __res_state *)malloc(sizeof *res); + if (!res) { + errno = ENOMEM; + return (NULL); + } + memset(res, 0, sizeof *res); + ho_res_set(this, res, free); + } + + return (pvt->res); +} + +static void +ho_res_set(struct irs_ho *this, struct __res_state *res, + void (*free_res)(void *)) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->res && pvt->free_res) { + res_nclose(pvt->res); + (*pvt->free_res)(pvt->res); + } + + pvt->res = res; + pvt->free_res = free_res; +} + +struct nis_res_target { + struct nis_res_target *next; + int family; +}; + +/* XXX */ +extern struct addrinfo *hostent2addrinfo __P((struct hostent *, + const struct addrinfo *pai)); + +static struct addrinfo * +ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai) +{ + struct pvt *pvt = (struct pvt *)this->private; + struct hostent *hp; + struct nis_res_target q, q2, *p; + struct addrinfo sentinel, *cur; + + memset(&q, 0, sizeof(q2)); + memset(&q2, 0, sizeof(q2)); + memset(&sentinel, 0, sizeof(sentinel)); + cur = &sentinel; + + switch(pai->ai_family) { + case AF_UNSPEC: /*%< INET6 then INET4 */ + q.family = AF_INET6; + q.next = &q2; + q2.family = AF_INET; + break; + case AF_INET6: + q.family = AF_INET6; + break; + case AF_INET: + q.family = AF_INET; + break; + default: + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); /*%< ??? */ + return(NULL); + } + + for (p = &q; p; p = p->next) { + struct addrinfo *ai; + + hp = (*this->byname2)(this, name, p->family); + if (hp == NULL) { + /* byname2 should've set an appropriate error */ + continue; + } + if ((hp->h_name == NULL) || (hp->h_name[0] == 0) || + (hp->h_addr_list[0] == NULL)) { + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); + continue; + } + ai = hostent2addrinfo(hp, pai); + if (ai) { + cur->ai_next = ai; + while (cur && cur->ai_next) + cur = cur->ai_next; + } + } + + if (sentinel.ai_next == NULL) + RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); + + return(sentinel.ai_next); +} + +/* Private */ + +/*% +ipnodes: +::1 localhost +127.0.0.1 localhost +1.2.3.4 FOO bar +1.2.6.4 FOO bar +1.2.6.5 host + +ipnodes.byname: +YP_MULTI_localhost ::1,127.0.0.1 localhost +YP_MULTI_foo 1.2.3.4,1.2.6.4 FOO bar +YP_MULTI_bar 1.2.3.4,1.2.6.4 FOO bar +host 1.2.6.5 host + +hosts.byname: +localhost 127.0.0.1 localhost +host 1.2.6.5 host +YP_MULTI_foo 1.2.3.4,1.2.6.4 FOO bar +YP_MULTI_bar 1.2.3.4,1.2.6.4 FOO bar +*/ + +static struct hostent * +makehostent(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + static const char spaces[] = " \t"; + char *cp, **q, *p, *comma, *ap; + int af = 0, len = 0; + int multi = 0; + int addr = 0; + + p = pvt->curval_data; + if ((cp = strpbrk(p, "#\n")) != NULL) + *cp = '\0'; + if (!(cp = strpbrk(p, spaces))) + return (NULL); + *cp++ = '\0'; + ap = pvt->hostbuf; + do { + if ((comma = strchr(p, ',')) != NULL) { + *comma++ = '\0'; + multi = 1; + } + if ((ap + IN6ADDRSZ) > (pvt->hostbuf + sizeof(pvt->hostbuf))) + break; + if ((pvt->res->options & RES_USE_INET6) && + inet_pton(AF_INET6, p, ap) > 0) { + af = AF_INET6; + len = IN6ADDRSZ; + } else if (inet_pton(AF_INET, p, pvt->host_addr) > 0) { + if (pvt->res->options & RES_USE_INET6) { + map_v4v6_address((char*)pvt->host_addr, ap); + af = AF_INET6; + len = IN6ADDRSZ; + } else { + af = AF_INET; + len = INADDRSZ; + } + } else { + if (!multi) + return (NULL); + continue; + } + if (addr < MAXADDRS) { + pvt->h_addr_ptrs[addr++] = ap; + pvt->h_addr_ptrs[addr] = NULL; + ap += len; + } + } while ((p = comma) != NULL); + if (ap == pvt->hostbuf) + return (NULL); + pvt->host.h_addr_list = pvt->h_addr_ptrs; + pvt->host.h_length = len; + pvt->host.h_addrtype = af; + cp += strspn(cp, spaces); + pvt->host.h_name = cp; + q = pvt->host.h_aliases = pvt->host_aliases; + if ((cp = strpbrk(cp, spaces)) != NULL) + *cp++ = '\0'; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &pvt->host_aliases[MAXALIASES]) + *q++ = cp; + if ((cp = strpbrk(cp, spaces)) != NULL) + *cp++ = '\0'; + } + *q = NULL; + RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS); + return (&pvt->host); +} + +static void +nisfree(struct pvt *pvt, enum do_what do_what) { + if ((do_what & do_key) && pvt->curkey_data) { + free(pvt->curkey_data); + pvt->curkey_data = NULL; + } + if ((do_what & do_val) && pvt->curval_data) { + free(pvt->curval_data); + pvt->curval_data = NULL; + } +} + +static int +init(struct irs_ho *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->res && !ho_res_get(this)) + return (-1); + if (((pvt->res->options & RES_INIT) == 0) && + res_ninit(pvt->res) == -1) + return (-1); + return (0); +} +#endif /*WANT_IRS_NIS*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/nis_ng.c b/contrib/bind-9.5.2/lib/bind/irs/nis_ng.c new file mode 100644 index 0000000000..ac6330536a --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/nis_ng.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: nis_ng.c,v 1.4 2005/04/27 04:56:32 sra Exp $"; +#endif + +/* Imports */ + +#include "port_before.h" + +#ifndef WANT_IRS_NIS +static int __bind_irs_nis_unneeded; +#else + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#ifdef T_NULL +#undef T_NULL /* Silence re-definition warning of T_NULL. */ +#endif +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "nis_p.h" + +/* Definitions */ + +struct tmpgrp { + const char * name; + const char * host; + const char * user; + const char * domain; + struct tmpgrp * next; +}; + +struct pvt { + char * nis_domain; + struct tmpgrp * tmp; + struct tmpgrp * cur; + char * tmpgroup; +}; + +enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 }; + +static /*const*/ char netgroup_map[] = "netgroup"; + +/* Forward */ + +static void ng_close(struct irs_ng *); +static int ng_next(struct irs_ng *, const char **, + const char **, const char **); +static int ng_test(struct irs_ng *, + const char *, const char *, + const char *, const char *); +static void ng_rewind(struct irs_ng *, const char *); +static void ng_minimize(struct irs_ng *); + +static void add_group_to_list(struct pvt *, const char *, int); +static void add_tuple_to_list(struct pvt *, const char *, char *); +static void tmpfree(struct pvt *); + +/* Public */ + +struct irs_ng * +irs_nis_ng(struct irs_acc *this) { + struct irs_ng *ng; + struct pvt *pvt; + + if (!(ng = memget(sizeof *ng))) { + errno = ENOMEM; + return (NULL); + } + memset(ng, 0x5e, sizeof *ng); + if (!(pvt = memget(sizeof *pvt))) { + memput(ng, sizeof *ng); + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + pvt->nis_domain = ((struct nis_p *)this->private)->domain; + ng->private = pvt; + ng->close = ng_close; + ng->next = ng_next; + ng->test = ng_test; + ng->rewind = ng_rewind; + ng->minimize = ng_minimize; + return (ng); +} + +/* Methods */ + +static void +ng_close(struct irs_ng *this) { + struct pvt *pvt = (struct pvt *)this->private; + + tmpfree(pvt); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static int +ng_next(struct irs_ng *this, const char **host, const char **user, const char **domain) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->cur) + return (0); + *host = pvt->cur->host; + *user = pvt->cur->user; + *domain = pvt->cur->domain; + pvt->cur = pvt->cur->next; + return (1); +} + +static int +ng_test(struct irs_ng *this, const char *name, + const char *host, const char *user, const char *domain) +{ + struct pvt *pvt = (struct pvt *)this->private; + struct tmpgrp *cur; + + tmpfree(pvt); + add_group_to_list(pvt, name, strlen(name)); + for (cur = pvt->tmp; cur; cur = cur->next) { + if ((!host || !cur->host || !strcmp(host, cur->host)) && + (!user || !cur->user || !strcmp(user, cur->user)) && + (!domain || !cur->domain || !strcmp(domain, cur->domain))) + break; + } + tmpfree(pvt); + return ((cur == NULL) ? 0 : 1); +} + +static void +ng_rewind(struct irs_ng *this, const char *name) { + struct pvt *pvt = (struct pvt *)this->private; + + /* Either hand back or free the existing list. */ + if (pvt->tmpgroup) { + if (pvt->tmp && !strcmp(pvt->tmpgroup, name)) + goto reset; + tmpfree(pvt); + } + pvt->tmpgroup = strdup(name); + add_group_to_list(pvt, name, strlen(name)); + reset: + pvt->cur = pvt->tmp; +} + +static void +ng_minimize(struct irs_ng *this) { + UNUSED(this); + /* NOOP */ +} + +/* Private */ + +static void +add_group_to_list(struct pvt *pvt, const char *name, int len) { + char *vdata, *cp, *np; + struct tmpgrp *tmp; + int vlen, r; + char *nametmp; + + /* Don't add the same group to the list more than once. */ + for (tmp = pvt->tmp; tmp; tmp = tmp->next) + if (!strcmp(tmp->name, name)) + return; + + DE_CONST(name, nametmp); + r = yp_match(pvt->nis_domain, netgroup_map, nametmp, len, + &vdata, &vlen); + if (r == 0) { + cp = vdata; + if (*cp && cp[strlen(cp)-1] == '\n') + cp[strlen(cp)-1] = '\0'; + for ( ; cp; cp = np) { + np = strchr(cp, ' '); + if (np) + *np++ = '\0'; + if (*cp == '(') + add_tuple_to_list(pvt, name, cp); + else + add_group_to_list(pvt, cp, strlen(cp)); + } + free(vdata); + } +} + +static void +add_tuple_to_list(struct pvt *pvt, const char *name, char *cp) { + struct tmpgrp *tmp; + char *tp, *np; + + INSIST(*cp++ == '('); + + tmp = malloc(sizeof *tmp + strlen(name) + sizeof '\0' + + strlen(cp) - sizeof ')'); + if (!tmp) + return; + memset(tmp, 0, sizeof *tmp); + tp = ((char *)tmp) + sizeof *tmp; + + /* Name */ + strcpy(tp, name); + tmp->name = tp; + tp += strlen(tp) + 1; + + /* Host */ + if (!(np = strchr(cp, ','))) + goto cleanup; + *np++ = '\0'; + strcpy(tp, cp); + tmp->host = tp; + tp += strlen(tp) + 1; + cp = np; + + /* User */ + if (!(np = strchr(cp, ','))) + goto cleanup; + *np++ = '\0'; + strcpy(tp, cp); + tmp->user = tp; + tp += strlen(tp) + 1; + cp = np; + + /* Domain */ + if (!(np = strchr(cp, ')'))) + goto cleanup; + *np++ = '\0'; + strcpy(tp, cp); + tmp->domain = tp; + + /* + * Empty string in file means wildcard, but + * NULL string in return value means wildcard. + */ + if (!*tmp->host) + tmp->host = NULL; + if (!*tmp->user) + tmp->user = NULL; + if (!*tmp->domain) + tmp->domain = NULL; + + /* Add to list (LIFO). */ + tmp->next = pvt->tmp; + pvt->tmp = tmp; + return; + + cleanup: + free(tmp); +} + +static void +tmpfree(struct pvt *pvt) { + struct tmpgrp *cur, *next; + + if (pvt->tmpgroup) { + free(pvt->tmpgroup); + pvt->tmpgroup = NULL; + } + for (cur = pvt->tmp; cur; cur = next) { + next = cur->next; + free(cur); + } + pvt->tmp = NULL; +} + +#endif /*WANT_IRS_NIS*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/nis_nw.c b/contrib/bind-9.5.2/lib/bind/irs/nis_nw.c new file mode 100644 index 0000000000..c61e871ea9 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/nis_nw.c @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: nis_nw.c,v 1.4 2005/04/27 04:56:33 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* Imports */ + +#include "port_before.h" + +#ifndef WANT_IRS_NIS +static int __bind_irs_nis_unneeded; +#else + +#include +#include + +#include +#include +#include +#ifdef T_NULL +#undef T_NULL /* Silence re-definition warning of T_NULL. */ +#endif +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "nis_p.h" + +/* Definitions */ + +#define MAXALIASES 35 +#define MAXADDRSIZE 4 + +struct pvt { + int needrewind; + char * nis_domain; + char * curkey_data; + int curkey_len; + char * curval_data; + int curval_len; + + struct nwent nwent; + char * nwbuf; + + char * aliases[MAXALIASES + 1]; + u_char addr[MAXADDRSIZE]; + + struct __res_state * res; + void (*free_res)(void *); +}; + +enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 }; + +static /*const*/ char networks_byname[] = "networks.byname"; +static /*const*/ char networks_byaddr[] = "networks.byaddr"; + +/* Forward */ + +static void nw_close(struct irs_nw *); +static struct nwent * nw_byname(struct irs_nw *, const char *, int); +static struct nwent * nw_byaddr(struct irs_nw *, void *, int, int); +static struct nwent * nw_next(struct irs_nw *); +static void nw_rewind(struct irs_nw *); +static void nw_minimize(struct irs_nw *); +static struct __res_state * nw_res_get(struct irs_nw *this); +static void nw_res_set(struct irs_nw *this, + struct __res_state *res, + void (*free_res)(void *)); + +static struct nwent * makenwent(struct irs_nw *this); +static void nisfree(struct pvt *, enum do_what); +static int init(struct irs_nw *this); + +/* Public */ + +struct irs_nw * +irs_nis_nw(struct irs_acc *this) { + struct irs_nw *nw; + struct pvt *pvt; + + if (!(pvt = memget(sizeof *pvt))) { + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + if (!(nw = memget(sizeof *nw))) { + memput(pvt, sizeof *pvt); + errno = ENOMEM; + return (NULL); + } + memset(nw, 0x5e, sizeof *nw); + pvt->needrewind = 1; + pvt->nis_domain = ((struct nis_p *)this->private)->domain; + nw->private = pvt; + nw->close = nw_close; + nw->byname = nw_byname; + nw->byaddr = nw_byaddr; + nw->next = nw_next; + nw->rewind = nw_rewind; + nw->minimize = nw_minimize; + nw->res_get = nw_res_get; + nw->res_set = nw_res_set; + return (nw); +} + +/* Methods */ + +static void +nw_close(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + nw_minimize(this); + if (pvt->res && pvt->free_res) + (*pvt->free_res)(pvt->res); + if (pvt->nwbuf) + free(pvt->nwbuf); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct nwent * +nw_byaddr(struct irs_nw *this, void *net, int length, int af) { + struct pvt *pvt = (struct pvt *)this->private; + char tmp[sizeof "255.255.255.255/32"], *t; + int r; + + if (init(this) == -1) + return (NULL); + + if (af != AF_INET) { + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + errno = EAFNOSUPPORT; + return (NULL); + } + nisfree(pvt, do_val); + /* Try it with /CIDR first. */ + if (inet_net_ntop(AF_INET, net, length, tmp, sizeof tmp) == NULL) { + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + return (NULL); + } + r = yp_match(pvt->nis_domain, networks_byaddr, tmp, strlen(tmp), + &pvt->curval_data, &pvt->curval_len); + if (r != 0) { + /* Give it a shot without the /CIDR. */ + if ((t = strchr(tmp, '/')) != NULL) { + *t = '\0'; + r = yp_match(pvt->nis_domain, networks_byaddr, + tmp, strlen(tmp), + &pvt->curval_data, &pvt->curval_len); + } + if (r != 0) { + RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); + return (NULL); + } + } + return (makenwent(this)); +} + +static struct nwent * +nw_byname(struct irs_nw *this, const char *name, int af) { + struct pvt *pvt = (struct pvt *)this->private; + int r; + char *tmp; + + if (init(this) == -1) + return (NULL); + + if (af != AF_INET) { + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); + errno = EAFNOSUPPORT; + return (NULL); + } + nisfree(pvt, do_val); + DE_CONST(name, tmp); + r = yp_match(pvt->nis_domain, networks_byname, tmp, + strlen(tmp), &pvt->curval_data, &pvt->curval_len); + if (r != 0) { + RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); + return (NULL); + } + return (makenwent(this)); +} + +static void +nw_rewind(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + pvt->needrewind = 1; +} + +static struct nwent * +nw_next(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct nwent *rval; + int r; + + if (init(this) == -1) + return (NULL); + + do { + if (pvt->needrewind) { + nisfree(pvt, do_all); + r = yp_first(pvt->nis_domain, networks_byaddr, + &pvt->curkey_data, &pvt->curkey_len, + &pvt->curval_data, &pvt->curval_len); + pvt->needrewind = 0; + } else { + char *newkey_data; + int newkey_len; + + nisfree(pvt, do_val); + r = yp_next(pvt->nis_domain, networks_byaddr, + pvt->curkey_data, pvt->curkey_len, + &newkey_data, &newkey_len, + &pvt->curval_data, &pvt->curval_len); + nisfree(pvt, do_key); + pvt->curkey_data = newkey_data; + pvt->curkey_len = newkey_len; + } + if (r != 0) { + RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); + return (NULL); + } + rval = makenwent(this); + } while (rval == NULL); + return (rval); +} + +static void +nw_minimize(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->res) + res_nclose(pvt->res); +} + +static struct __res_state * +nw_res_get(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->res) { + struct __res_state *res; + res = (struct __res_state *)malloc(sizeof *res); + if (!res) { + errno = ENOMEM; + return (NULL); + } + memset(res, 0, sizeof *res); + nw_res_set(this, res, free); + } + + return (pvt->res); +} + +static void +nw_res_set(struct irs_nw *this, struct __res_state *res, + void (*free_res)(void *)) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->res && pvt->free_res) { + res_nclose(pvt->res); + (*pvt->free_res)(pvt->res); + } + + pvt->res = res; + pvt->free_res = free_res; +} + +/* Private */ + +static struct nwent * +makenwent(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + static const char spaces[] = " \t"; + char *t, *cp, **ap; + + if (pvt->nwbuf) + free(pvt->nwbuf); + pvt->nwbuf = pvt->curval_data; + pvt->curval_data = NULL; + + if ((cp = strpbrk(pvt->nwbuf, "#\n")) != NULL) + *cp = '\0'; + cp = pvt->nwbuf; + + /* Name */ + pvt->nwent.n_name = cp; + cp += strcspn(cp, spaces); + if (!*cp) + goto cleanup; + *cp++ = '\0'; + cp += strspn(cp, spaces); + + /* Network */ + pvt->nwent.n_addrtype = AF_INET; + t = cp + strcspn(cp, spaces); + if (*t) + *t++ = '\0'; + pvt->nwent.n_length = inet_net_pton(AF_INET, cp, + pvt->addr, sizeof pvt->addr); + if (pvt->nwent.n_length < 0) + goto cleanup; + pvt->nwent.n_addr = pvt->addr; + cp = t; + + /* Aliases */ + ap = pvt->nwent.n_aliases = pvt->aliases; + while (*cp) { + if (ap >= &pvt->aliases[MAXALIASES]) + break; + *ap++ = cp; + cp += strcspn(cp, spaces); + if (!*cp) + break; + *cp++ = '\0'; + cp += strspn(cp, spaces); + } + *ap = NULL; + + return (&pvt->nwent); + + cleanup: + if (pvt->nwbuf) { + free(pvt->nwbuf); + pvt->nwbuf = NULL; + } + return (NULL); +} + +static void +nisfree(struct pvt *pvt, enum do_what do_what) { + if ((do_what & do_key) && pvt->curkey_data) { + free(pvt->curkey_data); + pvt->curkey_data = NULL; + } + if ((do_what & do_val) && pvt->curval_data) { + free(pvt->curval_data); + pvt->curval_data = NULL; + } +} + +static int +init(struct irs_nw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (!pvt->res && !nw_res_get(this)) + return (-1); + if (((pvt->res->options & RES_INIT) == 0) && + res_ninit(pvt->res) == -1) + return (-1); + return (0); +} + +#endif /*WANT_IRS_NIS*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/nis_p.h b/contrib/bind-9.5.2/lib/bind/irs/nis_p.h new file mode 100644 index 0000000000..70e2948d67 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/nis_p.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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: nis_p.h,v 1.3 2005/04/27 04:56:33 sra Exp $ + */ + +/*! \file + * \brief + * nis_p.h - private include file for the NIS functions. + */ + +/*% + * Object state. + */ +struct nis_p { + char * domain; + struct __res_state * res; + void (*free_res) __P((void *)); +}; + + +/* + * Methods. + */ + +extern struct irs_gr * irs_nis_gr __P((struct irs_acc *)); +extern struct irs_pw * irs_nis_pw __P((struct irs_acc *)); +extern struct irs_sv * irs_nis_sv __P((struct irs_acc *)); +extern struct irs_pr * irs_nis_pr __P((struct irs_acc *)); +extern struct irs_ho * irs_nis_ho __P((struct irs_acc *)); +extern struct irs_nw * irs_nis_nw __P((struct irs_acc *)); +extern struct irs_ng * irs_nis_ng __P((struct irs_acc *)); diff --git a/contrib/bind-9.5.2/lib/bind/irs/nis_pr.c b/contrib/bind-9.5.2/lib/bind/irs/nis_pr.c new file mode 100644 index 0000000000..4995550f82 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/nis_pr.c @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: nis_pr.c,v 1.4 2005/04/27 04:56:33 sra Exp $"; +#endif + +/* Imports */ + +#include "port_before.h" + +#ifndef WANT_IRS_NIS +static int __bind_irs_nis_unneeded; +#else + +#include +#include +#include +#include +#ifdef T_NULL +#undef T_NULL /* Silence re-definition warning of T_NULL. */ +#endif +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "nis_p.h" + +/* Definitions */ + +struct pvt { + int needrewind; + char * nis_domain; + char * curkey_data; + int curkey_len; + char * curval_data; + int curval_len; + struct protoent proto; + char * prbuf; +}; + +enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 }; + +static /*const*/ char protocols_byname[] = "protocols.byname"; +static /*const*/ char protocols_bynumber[] = "protocols.bynumber"; + +/* Forward */ + +static void pr_close(struct irs_pr *); +static struct protoent * pr_byname(struct irs_pr *, const char *); +static struct protoent * pr_bynumber(struct irs_pr *, int); +static struct protoent * pr_next(struct irs_pr *); +static void pr_rewind(struct irs_pr *); +static void pr_minimize(struct irs_pr *); + +static struct protoent * makeprotoent(struct irs_pr *this); +static void nisfree(struct pvt *, enum do_what); + +/* Public */ + +struct irs_pr * +irs_nis_pr(struct irs_acc *this) { + struct irs_pr *pr; + struct pvt *pvt; + + if (!(pr = memget(sizeof *pr))) { + errno = ENOMEM; + return (NULL); + } + memset(pr, 0x5e, sizeof *pr); + if (!(pvt = memget(sizeof *pvt))) { + memput(pr, sizeof *pr); + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + pvt->needrewind = 1; + pvt->nis_domain = ((struct nis_p *)this->private)->domain; + pr->private = pvt; + pr->byname = pr_byname; + pr->bynumber = pr_bynumber; + pr->next = pr_next; + pr->rewind = pr_rewind; + pr->close = pr_close; + pr->minimize = pr_minimize; + pr->res_get = NULL; + pr->res_set = NULL; + return (pr); +} + +/* Methods. */ + +static void +pr_close(struct irs_pr *this) { + struct pvt *pvt = (struct pvt *)this->private; + + nisfree(pvt, do_all); + if (pvt->proto.p_aliases) + free(pvt->proto.p_aliases); + if (pvt->prbuf) + free(pvt->prbuf); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct protoent * +pr_byname(struct irs_pr *this, const char *name) { + struct pvt *pvt = (struct pvt *)this->private; + int r; + char *tmp; + + nisfree(pvt, do_val); + DE_CONST(name, tmp); + r = yp_match(pvt->nis_domain, protocols_byname, tmp, + strlen(tmp), &pvt->curval_data, &pvt->curval_len); + if (r != 0) { + errno = ENOENT; + return (NULL); + } + return (makeprotoent(this)); +} + +static struct protoent * +pr_bynumber(struct irs_pr *this, int num) { + struct pvt *pvt = (struct pvt *)this->private; + char tmp[sizeof "-4294967295"]; + int r; + + nisfree(pvt, do_val); + (void) sprintf(tmp, "%d", num); + r = yp_match(pvt->nis_domain, protocols_bynumber, tmp, strlen(tmp), + &pvt->curval_data, &pvt->curval_len); + if (r != 0) { + errno = ENOENT; + return (NULL); + } + return (makeprotoent(this)); +} + +static struct protoent * +pr_next(struct irs_pr *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct protoent *rval; + int r; + + do { + if (pvt->needrewind) { + nisfree(pvt, do_all); + r = yp_first(pvt->nis_domain, protocols_bynumber, + &pvt->curkey_data, &pvt->curkey_len, + &pvt->curval_data, &pvt->curval_len); + pvt->needrewind = 0; + } else { + char *newkey_data; + int newkey_len; + + nisfree(pvt, do_val); + r = yp_next(pvt->nis_domain, protocols_bynumber, + pvt->curkey_data, pvt->curkey_len, + &newkey_data, &newkey_len, + &pvt->curval_data, &pvt->curval_len); + nisfree(pvt, do_key); + pvt->curkey_data = newkey_data; + pvt->curkey_len = newkey_len; + } + if (r != 0) { + errno = ENOENT; + return (NULL); + } + rval = makeprotoent(this); + } while (rval == NULL); + return (rval); +} + +static void +pr_rewind(struct irs_pr *this) { + struct pvt *pvt = (struct pvt *)this->private; + + pvt->needrewind = 1; +} + +static void +pr_minimize(struct irs_pr *this) { + UNUSED(this); + /* NOOP */ +} + +/* Private */ + +static struct protoent * +makeprotoent(struct irs_pr *this) { + struct pvt *pvt = (struct pvt *)this->private; + char *p, **t; + int n, m; + + if (pvt->prbuf) + free(pvt->prbuf); + pvt->prbuf = pvt->curval_data; + pvt->curval_data = NULL; + + for (p = pvt->prbuf; *p && *p != '#';) + p++; + while (p > pvt->prbuf && isspace((unsigned char)(p[-1]))) + p--; + *p = '\0'; + + p = pvt->prbuf; + n = m = 0; + + pvt->proto.p_name = p; + while (*p && !isspace((unsigned char)*p)) + p++; + if (!*p) + return (NULL); + *p++ = '\0'; + + while (*p && isspace((unsigned char)*p)) + p++; + pvt->proto.p_proto = atoi(p); + while (*p && !isspace((unsigned char)*p)) + p++; + *p++ = '\0'; + + while (*p) { + if ((n + 1) >= m || !pvt->proto.p_aliases) { + m += 10; + t = realloc(pvt->proto.p_aliases, + m * sizeof(char *)); + if (!t) { + errno = ENOMEM; + goto cleanup; + } + pvt->proto.p_aliases = t; + } + pvt->proto.p_aliases[n++] = p; + while (*p && !isspace((unsigned char)*p)) + p++; + if (*p) + *p++ = '\0'; + } + if (!pvt->proto.p_aliases) + pvt->proto.p_aliases = malloc(sizeof(char *)); + if (!pvt->proto.p_aliases) + goto cleanup; + pvt->proto.p_aliases[n] = NULL; + return (&pvt->proto); + + cleanup: + if (pvt->proto.p_aliases) { + free(pvt->proto.p_aliases); + pvt->proto.p_aliases = NULL; + } + if (pvt->prbuf) { + free(pvt->prbuf); + pvt->prbuf = NULL; + } + return (NULL); +} + +static void +nisfree(struct pvt *pvt, enum do_what do_what) { + if ((do_what & do_key) && pvt->curkey_data) { + free(pvt->curkey_data); + pvt->curkey_data = NULL; + } + if ((do_what & do_val) && pvt->curval_data) { + free(pvt->curval_data); + pvt->curval_data = NULL; + } +} + +#endif /*WANT_IRS_NIS*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/nis_pw.c b/contrib/bind-9.5.2/lib/bind/irs/nis_pw.c new file mode 100644 index 0000000000..8f27e4bd93 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/nis_pw.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: nis_pw.c,v 1.4 2005/04/27 04:56:33 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* Imports */ + +#include "port_before.h" + +#if !defined(WANT_IRS_PW) || !defined(WANT_IRS_NIS) +static int __bind_irs_pw_unneeded; +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "nis_p.h" + +/* Definitions */ + +struct pvt { + int needrewind; + char * nis_domain; + char * curkey_data; + int curkey_len; + char * curval_data; + int curval_len; + struct passwd passwd; + char * pwbuf; +}; + +enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 }; + +static /*const*/ char passwd_byname[] = "passwd.byname"; +static /*const*/ char passwd_byuid[] = "passwd.byuid"; + +/* Forward */ + +static void pw_close(struct irs_pw *); +static struct passwd * pw_next(struct irs_pw *); +static struct passwd * pw_byname(struct irs_pw *, const char *); +static struct passwd * pw_byuid(struct irs_pw *, uid_t); +static void pw_rewind(struct irs_pw *); +static void pw_minimize(struct irs_pw *); + +static struct passwd * makepasswdent(struct irs_pw *); +static void nisfree(struct pvt *, enum do_what); + +/* Public */ + +struct irs_pw * +irs_nis_pw(struct irs_acc *this) { + struct irs_pw *pw; + struct pvt *pvt; + + if (!(pw = memget(sizeof *pw))) { + errno = ENOMEM; + return (NULL); + } + memset(pw, 0x5e, sizeof *pw); + if (!(pvt = memget(sizeof *pvt))) { + memput(pw, sizeof *pw); + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + pvt->needrewind = 1; + pvt->nis_domain = ((struct nis_p *)this->private)->domain; + pw->private = pvt; + pw->close = pw_close; + pw->next = pw_next; + pw->byname = pw_byname; + pw->byuid = pw_byuid; + pw->rewind = pw_rewind; + pw->minimize = pw_minimize; + pw->res_get = NULL; + pw->res_set = NULL; + return (pw); +} + +/* Methods */ + +static void +pw_close(struct irs_pw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + if (pvt->pwbuf) + free(pvt->pwbuf); + nisfree(pvt, do_all); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct passwd * +pw_next(struct irs_pw *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct passwd *rval; + int r; + + do { + if (pvt->needrewind) { + nisfree(pvt, do_all); + r = yp_first(pvt->nis_domain, passwd_byname, + &pvt->curkey_data, &pvt->curkey_len, + &pvt->curval_data, &pvt->curval_len); + pvt->needrewind = 0; + } else { + char *newkey_data; + int newkey_len; + + nisfree(pvt, do_val); + r = yp_next(pvt->nis_domain, passwd_byname, + pvt->curkey_data, pvt->curkey_len, + &newkey_data, &newkey_len, + &pvt->curval_data, &pvt->curval_len); + nisfree(pvt, do_key); + pvt->curkey_data = newkey_data; + pvt->curkey_len = newkey_len; + } + if (r != 0) { + errno = ENOENT; + return (NULL); + } + rval = makepasswdent(this); + } while (rval == NULL); + return (rval); +} + +static struct passwd * +pw_byname(struct irs_pw *this, const char *name) { + struct pvt *pvt = (struct pvt *)this->private; + int r; + char *tmp; + + nisfree(pvt, do_val); + DE_CONST(name, tmp); + r = yp_match(pvt->nis_domain, passwd_byname, tmp, strlen(tmp), + &pvt->curval_data, &pvt->curval_len); + if (r != 0) { + errno = ENOENT; + return (NULL); + } + return (makepasswdent(this)); +} + +static struct passwd * +pw_byuid(struct irs_pw *this, uid_t uid) { + struct pvt *pvt = (struct pvt *)this->private; + char tmp[sizeof "4294967295"]; + int r; + + nisfree(pvt, do_val); + (void) sprintf(tmp, "%u", (unsigned int)uid); + r = yp_match(pvt->nis_domain, passwd_byuid, tmp, strlen(tmp), + &pvt->curval_data, &pvt->curval_len); + if (r != 0) { + errno = ENOENT; + return (NULL); + } + return (makepasswdent(this)); +} + +static void +pw_rewind(struct irs_pw *this) { + struct pvt *pvt = (struct pvt *)this->private; + + pvt->needrewind = 1; +} + +static void +pw_minimize(struct irs_pw *this) { + UNUSED(this); + /* NOOP */ +} + +/* Private */ + +static struct passwd * +makepasswdent(struct irs_pw *this) { + struct pvt *pvt = (struct pvt *)this->private; + char *cp; + + memset(&pvt->passwd, 0, sizeof pvt->passwd); + if (pvt->pwbuf) + free(pvt->pwbuf); + pvt->pwbuf = pvt->curval_data; + pvt->curval_data = NULL; + + cp = pvt->pwbuf; + pvt->passwd.pw_name = cp; + if (!(cp = strchr(cp, ':'))) + goto cleanup; +#ifdef HAS_PW_CLASS + pvt->passwd.pw_class = cp; /*%< Needs to point at a \0. */ +#endif + *cp++ = '\0'; + + pvt->passwd.pw_passwd = cp; + if (!(cp = strchr(cp, ':'))) + goto cleanup; + *cp++ = '\0'; + + pvt->passwd.pw_uid = atoi(cp); + if (!(cp = strchr(cp, ':'))) + goto cleanup; + *cp++ = '\0'; + + pvt->passwd.pw_gid = atoi(cp); + if (!(cp = strchr(cp, ':'))) + goto cleanup; + *cp++ = '\0'; + + pvt->passwd.pw_gecos = cp; + if (!(cp = strchr(cp, ':'))) + goto cleanup; + *cp++ = '\0'; + + pvt->passwd.pw_dir = cp; + if (!(cp = strchr(cp, ':'))) + goto cleanup; + *cp++ = '\0'; + + pvt->passwd.pw_shell = cp; + + if ((cp = strchr(cp, '\n')) != NULL) + *cp = '\0'; + + return (&pvt->passwd); + + cleanup: + free(pvt->pwbuf); + pvt->pwbuf = NULL; + return (NULL); +} + +static void +nisfree(struct pvt *pvt, enum do_what do_what) { + if ((do_what & do_key) && pvt->curkey_data) { + free(pvt->curkey_data); + pvt->curkey_data = NULL; + } + if ((do_what & do_val) && pvt->curval_data) { + free(pvt->curval_data); + pvt->curval_data = NULL; + } +} + +#endif /* WANT_IRS_PW && WANT_IRS_NIS */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/nis_sv.c b/contrib/bind-9.5.2/lib/bind/irs/nis_sv.c new file mode 100644 index 0000000000..bb24600f0d --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/nis_sv.c @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: nis_sv.c,v 1.4 2005/04/27 04:56:34 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* Imports */ + +#include "port_before.h" + +#ifndef WANT_IRS_NIS +static int __bind_irs_nis_unneeded; +#else + +#include +#include +#include +#include +#include +#ifdef T_NULL +#undef T_NULL /* Silence re-definition warning of T_NULL. */ +#endif +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "nis_p.h" + +/* Definitions */ + +struct pvt { + int needrewind; + char * nis_domain; + char * curkey_data; + int curkey_len; + char * curval_data; + int curval_len; + char line[BUFSIZ+1]; + struct servent serv; + char * svbuf; +}; + +enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 }; + +static /*const*/ char services_byname[] = "services.byname"; + +/* Forward */ + +static void sv_close(struct irs_sv*); +static struct servent * sv_next(struct irs_sv *); +static struct servent * sv_byname(struct irs_sv *, const char *, + const char *); +static struct servent * sv_byport(struct irs_sv *, int, const char *); +static void sv_rewind(struct irs_sv *); +static void sv_minimize(struct irs_sv *); + +static struct servent * makeservent(struct irs_sv *this); +static void nisfree(struct pvt *, enum do_what); + +/* Public */ + +struct irs_sv * +irs_nis_sv(struct irs_acc *this) { + struct irs_sv *sv; + struct pvt *pvt; + + if (!(sv = memget(sizeof *sv))) { + errno = ENOMEM; + return (NULL); + } + memset(sv, 0x5e, sizeof *sv); + if (!(pvt = memget(sizeof *pvt))) { + memput(sv, sizeof *sv); + errno = ENOMEM; + return (NULL); + } + memset(pvt, 0, sizeof *pvt); + pvt->needrewind = 1; + pvt->nis_domain = ((struct nis_p *)this->private)->domain; + sv->private = pvt; + sv->close = sv_close; + sv->next = sv_next; + sv->byname = sv_byname; + sv->byport = sv_byport; + sv->rewind = sv_rewind; + sv->minimize = sv_minimize; + sv->res_get = NULL; + sv->res_set = NULL; + return (sv); +} + +/* Methods */ + +static void +sv_close(struct irs_sv *this) { + struct pvt *pvt = (struct pvt *)this->private; + + nisfree(pvt, do_all); + if (pvt->serv.s_aliases) + free(pvt->serv.s_aliases); + if (pvt->svbuf) + free(pvt->svbuf); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); +} + +static struct servent * +sv_byname(struct irs_sv *this, const char *name, const char *proto) { + struct servent *serv; + char **sap; + + sv_rewind(this); + while ((serv = sv_next(this)) != NULL) { + if (proto != NULL && strcmp(proto, serv->s_proto)) + continue; + if (!strcmp(name, serv->s_name)) + break; + for (sap = serv->s_aliases; sap && *sap; sap++) + if (!strcmp(name, *sap)) + break; + } + return (serv); +} + +static struct servent * +sv_byport(struct irs_sv *this, int port, const char *proto) { + struct servent *serv; + + sv_rewind(this); + while ((serv = sv_next(this)) != NULL) { + if (proto != NULL && strcmp(proto, serv->s_proto)) + continue; + if (serv->s_port == port) + break; + } + return (serv); +} + +static void +sv_rewind(struct irs_sv *this) { + struct pvt *pvt = (struct pvt *)this->private; + + pvt->needrewind = 1; +} + +static struct servent * +sv_next(struct irs_sv *this) { + struct pvt *pvt = (struct pvt *)this->private; + struct servent *rval; + int r; + + do { + if (pvt->needrewind) { + nisfree(pvt, do_all); + r = yp_first(pvt->nis_domain, services_byname, + &pvt->curkey_data, &pvt->curkey_len, + &pvt->curval_data, &pvt->curval_len); + pvt->needrewind = 0; + } else { + char *newkey_data; + int newkey_len; + + nisfree(pvt, do_val); + r = yp_next(pvt->nis_domain, services_byname, + pvt->curkey_data, pvt->curkey_len, + &newkey_data, &newkey_len, + &pvt->curval_data, &pvt->curval_len); + nisfree(pvt, do_key); + pvt->curkey_data = newkey_data; + pvt->curkey_len = newkey_len; + } + if (r != 0) { + errno = ENOENT; + return (NULL); + } + rval = makeservent(this); + } while (rval == NULL); + return (rval); +} + +static void +sv_minimize(struct irs_sv *this) { + UNUSED(this); + /* NOOP */ +} + +/* Private */ + +static struct servent * +makeservent(struct irs_sv *this) { + struct pvt *pvt = (struct pvt *)this->private; + static const char spaces[] = " \t"; + char *p, **t; + int n, m; + + if (pvt->svbuf) + free(pvt->svbuf); + pvt->svbuf = pvt->curval_data; + pvt->curval_data = NULL; + + if (pvt->serv.s_aliases) { + free(pvt->serv.s_aliases); + pvt->serv.s_aliases = NULL; + } + + if ((p = strpbrk(pvt->svbuf, "#\n"))) + *p = '\0'; + + p = pvt->svbuf; + + pvt->serv.s_name = p; + p += strcspn(p, spaces); + if (!*p) + goto cleanup; + *p++ = '\0'; + p += strspn(p, spaces); + + pvt->serv.s_port = htons((u_short) atoi(p)); + pvt->serv.s_proto = NULL; + + while (*p && !isspace((unsigned char)*p)) + if (*p++ == '/') + pvt->serv.s_proto = p; + if (!pvt->serv.s_proto) + goto cleanup; + if (*p) { + *p++ = '\0'; + p += strspn(p, spaces); + } + + n = m = 0; + while (*p) { + if ((n + 1) >= m || !pvt->serv.s_aliases) { + m += 10; + t = realloc(pvt->serv.s_aliases, m * sizeof(char *)); + if (!t) { + errno = ENOMEM; + goto cleanup; + } + pvt->serv.s_aliases = t; + } + pvt->serv.s_aliases[n++] = p; + p += strcspn(p, spaces); + if (!*p) + break; + *p++ = '\0'; + p += strspn(p, spaces); + } + if (!pvt->serv.s_aliases) + pvt->serv.s_aliases = malloc(sizeof(char *)); + if (!pvt->serv.s_aliases) + goto cleanup; + pvt->serv.s_aliases[n] = NULL; + return (&pvt->serv); + + cleanup: + if (pvt->serv.s_aliases) { + free(pvt->serv.s_aliases); + pvt->serv.s_aliases = NULL; + } + if (pvt->svbuf) { + free(pvt->svbuf); + pvt->svbuf = NULL; + } + return (NULL); +} + +static void +nisfree(struct pvt *pvt, enum do_what do_what) { + if ((do_what & do_key) && pvt->curkey_data) { + free(pvt->curkey_data); + pvt->curkey_data = NULL; + } + if ((do_what & do_val) && pvt->curval_data) { + free(pvt->curval_data); + pvt->curval_data = NULL; + } +} + +#endif /*WANT_IRS_NIS*/ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/nul_ng.c b/contrib/bind-9.5.2/lib/bind/irs/nul_ng.c new file mode 100644 index 0000000000..e5811b563c --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/nul_ng.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: nul_ng.c,v 1.3 2005/04/27 04:56:34 sra Exp $"; +#endif + +/*! \file + * \brief + * nul_ng.c - the netgroup accessor null map + */ + +#include "port_before.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#include "irs_p.h" +#include "hesiod.h" +#include "dns_p.h" + +/* Forward. */ + +static void ng_close(struct irs_ng *); +static int ng_next(struct irs_ng *, const char **, + const char **, const char **); +static int ng_test(struct irs_ng *, + const char *, const char *, + const char *, const char *); +static void ng_rewind(struct irs_ng *, const char *); +static void ng_minimize(struct irs_ng *); + +/* Public. */ + +struct irs_ng * +irs_nul_ng(struct irs_acc *this) { + struct irs_ng *ng; + + UNUSED(this); + + if (!(ng = memget(sizeof *ng))) { + errno = ENOMEM; + return (NULL); + } + memset(ng, 0x5e, sizeof *ng); + ng->private = NULL; + ng->close = ng_close; + ng->next = ng_next; + ng->test = ng_test; + ng->rewind = ng_rewind; + ng->minimize = ng_minimize; + return (ng); +} + +/* Methods. */ + +static void +ng_close(struct irs_ng *this) { + memput(this, sizeof *this); +} + +/* ARGSUSED */ +static int +ng_next(struct irs_ng *this, const char **host, const char **user, + const char **domain) +{ + UNUSED(this); + UNUSED(host); + UNUSED(user); + UNUSED(domain); + errno = ENOENT; + return (-1); +} + +static int +ng_test(struct irs_ng *this, const char *name, + const char *user, const char *host, const char *domain) +{ + UNUSED(this); + UNUSED(name); + UNUSED(user); + UNUSED(host); + UNUSED(domain); + errno = ENODEV; + return (-1); +} + +static void +ng_rewind(struct irs_ng *this, const char *netgroup) { + UNUSED(this); + UNUSED(netgroup); + /* NOOP */ +} + +static void +ng_minimize(struct irs_ng *this) { + UNUSED(this); + /* NOOP */ +} diff --git a/contrib/bind-9.5.2/lib/bind/irs/pathnames.h b/contrib/bind-9.5.2/lib/bind/irs/pathnames.h new file mode 100644 index 0000000000..1646842155 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/pathnames.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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: pathnames.h,v 1.3 2005/04/27 04:56:34 sra Exp $ + */ + +#ifndef _PATH_IRS_CONF +#define _PATH_IRS_CONF "/etc/irs.conf" +#endif + +#ifndef _PATH_NETWORKS +#define _PATH_NETWORKS "/etc/networks" +#endif + +#ifndef _PATH_GROUP +#define _PATH_GROUP "/etc/group" +#endif + +#ifndef _PATH_NETGROUP +#define _PATH_NETGROUP "/etc/netgroup" +#endif + +#ifndef _PATH_SERVICES +#define _PATH_SERVICES "/etc/services" +#endif + +#ifdef IRS_LCL_SV_DB +#ifndef _PATH_SERVICES_DB +#define _PATH_SERVICES_DB _PATH_SERVICES ".db" +#endif +#endif + +#ifndef _PATH_HESIOD_CONF +#define _PATH_HESIOD_CONF "/etc/hesiod.conf" +#endif + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/irs/util.c b/contrib/bind-9.5.2/lib/bind/irs/util.c new file mode 100644 index 0000000000..794c10b107 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/irs/util.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: util.c,v 1.3 2005/04/27 04:56:34 sra Exp $"; +#endif + +#include "port_before.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "port_after.h" + +#include "irs_p.h" + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) sprintf x +#endif + +void +map_v4v6_address(const char *src, char *dst) { + u_char *p = (u_char *)dst; + char tmp[NS_INADDRSZ]; + int i; + + /* Stash a temporary copy so our caller can update in place. */ + memcpy(tmp, src, NS_INADDRSZ); + /* Mark this ipv6 addr as a mapped ipv4. */ + for (i = 0; i < 10; i++) + *p++ = 0x00; + *p++ = 0xff; + *p++ = 0xff; + /* Retrieve the saved copy and we're done. */ + memcpy((void*)p, tmp, NS_INADDRSZ); +} + +int +make_group_list(struct irs_gr *this, const char *name, + gid_t basegid, gid_t *groups, int *ngroups) +{ + struct group *grp; + int i, ng; + int ret, maxgroups; + + ret = -1; + ng = 0; + maxgroups = *ngroups; + /* + * When installing primary group, duplicate it; + * the first element of groups is the effective gid + * and will be overwritten when a setgid file is executed. + */ + if (ng >= maxgroups) + goto done; + groups[ng++] = basegid; + if (ng >= maxgroups) + goto done; + groups[ng++] = basegid; + /* + * Scan the group file to find additional groups. + */ + (*this->rewind)(this); + while ((grp = (*this->next)(this)) != NULL) { + if ((gid_t)grp->gr_gid == basegid) + continue; + for (i = 0; grp->gr_mem[i]; i++) { + if (!strcmp(grp->gr_mem[i], name)) { + if (ng >= maxgroups) + goto done; + groups[ng++] = grp->gr_gid; + break; + } + } + } + ret = 0; + done: + *ngroups = ng; + return (ret); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/isc/assertions.c b/contrib/bind-9.5.2/lib/bind/isc/assertions.c new file mode 100644 index 0000000000..6ce0edaf04 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/assertions.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1997,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: assertions.c,v 1.3.672.1 2008/10/15 03:56:25 marka Exp $"; +#endif + +#include "port_before.h" + +#include +#include +#include +#include + +#include + +#include "port_after.h" + +/* + * Forward. + */ + +static void default_assertion_failed(const char *, int, assertion_type, + const char *, int); + +/* + * Public. + */ + +assertion_failure_callback __assertion_failed = default_assertion_failed; + +void +set_assertion_failure_callback(assertion_failure_callback f) { + if (f == NULL) + __assertion_failed = default_assertion_failed; + else + __assertion_failed = f; +} + +const char * +assertion_type_to_text(assertion_type type) { + const char *result; + + switch (type) { + case assert_require: + result = "REQUIRE"; + break; + case assert_ensure: + result = "ENSURE"; + break; + case assert_insist: + result = "INSIST"; + break; + case assert_invariant: + result = "INVARIANT"; + break; + default: + result = NULL; + } + return (result); +} + +/* + * Private. + */ + +/* coverity[+kill] */ +static void +default_assertion_failed(const char *file, int line, assertion_type type, + const char *cond, int print_errno) +{ + fprintf(stderr, "%s:%d: %s(%s)%s%s failed.\n", + file, line, assertion_type_to_text(type), cond, + (print_errno) ? ": " : "", + (print_errno) ? strerror(errno) : ""); + abort(); + /* NOTREACHED */ +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/isc/assertions.mdoc b/contrib/bind-9.5.2/lib/bind/isc/assertions.mdoc new file mode 100644 index 0000000000..4b77e569e3 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/assertions.mdoc @@ -0,0 +1,138 @@ +.\" $Id: assertions.mdoc,v 1.3 2004/03/09 06:30:06 marka Exp $ +.\" +.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (c) 1997,1999 by Internet Software Consortium. +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND 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. +.\" +.Dd November 17, 1997 +.Dt ASSERTIONS 3 +.Os ISC +.Sh NAME +.Nm REQUIRE , +.Nm REQUIRE_ERR , +.Nm ENSURE , +.Nm ENSURE_ERR , +.Nm INSIST , +.Nm INSIST_ERR , +.Nm INVARIANT , +.Nm INVARIANT_ERR , +.Nm set_assertion_failure_callback +.Nd assertion system +.Sh SYNOPSIS +.Fd #include +.Fo "typedef void (*assertion_failure_callback)" +.Fa "char *filename" +.Fa "int line" +.Fa "assertion_type type" +.Fa "char *condition" +.Fa "int print_errno" +.Fc +.Fn REQUIRE "int boolean_expression" +.Fn REQUIRE_ERR "int boolean_expression" +.Fn ENSURE "int boolean_expression" +.Fn ENSURE_ERR "int boolean_expression" +.Fn INSIST "int boolean_expression" +.Fn INSIST_ERR "int boolean_expression" +.Fn INVARIANT "int boolean_expression" +.Fn INVARIANT_ERR "int boolean_expression" +.Ft void +.Fn set_assertion_failure_callback "assertion_failure_callback callback" +.Ft char * +.Fn assertion_type_to_text "assertion_type type" +.Sh DESCRIPTION +The +.Fn REQUIRE , +.Fn ENSURE , +.Fn INSIST , +and +.Fn INVARIANT +macros evaluate a boolean expression, and if it is false, they invoke the +current assertion failure callback. The default callback will print a message +to +.Li stderr +describing the failure, and then cause the program to dump core. +If the +.Dq Fn _ERR +variant of the assertion is used, the callback will include +.Fn strerror "errno" +in its message. +.Pp +Each assertion type has an associated +.Li CHECK +macro. If this macro's value is +.Dq 0 +when +.Dq "" +is included, then assertions of that type will not be checked. E.g. +.Pp +.Dl #define CHECK_ENSURE 0 +.Pp +will disable checking of +.Fn ENSURE +and +.Fn ENSURE_ERR . +The macros +.Li CHECK_ALL +and +.Li CHECK_NONE +may also be used, respectively specifying that either all or none of the +assertion types should be checked. +.Pp +.Fn set_assertion_failure_callback +specifies the function to call when an assertion fails. +.Pp +When an +.Fn assertion_failure_callback +is called, the +.Fa filename +and +.Fa line +arguments specify the filename and line number of the failing assertion. +The +.Fa type +is one of: +.Bd -literal -offset indent +assert_require +assert_ensure +assert_insist +assert_invariant +.Ed +.Pp +and may be used by the callback to determine the type of the failing +assertion. +.Fa condition +is the literal text of the assertion that failed. +.Fa print_errno +will be non-zero if the callback should print +.Fa strerror "errno" +as part of its output. +.Pp +.Fn assertion_type_to_text +returns a textual representation of +.Fa type . +For example, +.Fn assertion_type_to_text "assert_require" +returns the string +.Dq REQUIRE . +.Sh SEE ALSO +.Rs +.%A Bertrand Meyer +.%B Object-Oriented Software Construction, 2nd edition +.%Q Prentice\-Hall +.%D 1997 +.%O ISBN 0\-13\-629155\-4 +.%P chapter 11 +.Re +.Sh AUTHOR +Bob Halley (ISC). diff --git a/contrib/bind-9.5.2/lib/bind/isc/base64.c b/contrib/bind-9.5.2/lib/bind/isc/base64.c new file mode 100644 index 0000000000..60b20bca5a --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/base64.c @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: base64.c,v 1.4 2005/04/27 04:56:34 sra Exp $"; +#endif /* not lint */ + +#include "port_before.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "port_after.h" + +#define Assert(Cond) if (!(Cond)) abort() + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) + The following encoding technique is taken from RFC1521 by Borenstein + and Freed. It is reproduced here in a slightly edited form for + convenience. + + A 65-character subset of US-ASCII is used, enabling 6 bits to be + represented per printable character. (The extra 65th character, "=", + is used to signify a special processing function.) + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8-bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + + Each 6-bit group is used as an index into an array of 64 printable + characters. The character referenced by the index is placed in the + output string. + + Table 1: The Base64 Alphabet + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w (pad) = + 15 P 32 g 49 x + 16 Q 33 h 50 y + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a quantity. When fewer than 24 input + bits are available in an input group, zero bits are added (on the + right) to form an integral number of 6-bit groups. Padding at the + end of the data is performed using the '=' character. + + Since all base64 input is an integral number of octets, only the + ------------------------------------------------- + following cases can arise: + + (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded + output will be an integral multiple of 4 characters + with no "=" padding, + (2) the final quantum of encoding input is exactly 8 bits; + here, the final unit of encoded output will be two + characters followed by two "=" padding characters, or + (3) the final quantum of encoding input is exactly 16 bits; + here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + +int +b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) { + size_t datalength = 0; + u_char input[3]; + u_char output[4]; + size_t i; + + while (2U < srclength) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + srclength -= 3; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = input[2] & 0x3f; + Assert(output[0] < 64); + Assert(output[1] < 64); + Assert(output[2] < 64); + Assert(output[3] < 64); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + target[datalength++] = Base64[output[2]]; + target[datalength++] = Base64[output[3]]; + } + + /* Now we worry about padding. */ + if (0U != srclength) { + /* Get what's left. */ + input[0] = input[1] = input[2] = '\0'; + for (i = 0; i < srclength; i++) + input[i] = *src++; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + Assert(output[0] < 64); + Assert(output[1] < 64); + Assert(output[2] < 64); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + if (srclength == 1U) + target[datalength++] = Pad64; + else + target[datalength++] = Base64[output[2]]; + target[datalength++] = Pad64; + } + if (datalength >= targsize) + return (-1); + target[datalength] = '\0'; /*%< Returned value doesn't count \\0. */ + return (datalength); +} + +/* skips all whitespace anywhere. + converts characters, four at a time, starting at (or after) + src from base - 64 numbers into three 8 bit bytes in the target area. + it returns the number of data bytes stored at the target, or -1 on error. + */ + +int +b64_pton(src, target, targsize) + char const *src; + u_char *target; + size_t targsize; +{ + int tarindex, state, ch; + char *pos; + + state = 0; + tarindex = 0; + + while ((ch = *src++) != '\0') { + if (isspace(ch)) /*%< Skip whitespace anywhere. */ + continue; + + if (ch == Pad64) + break; + + pos = strchr(Base64, ch); + if (pos == 0) /*%< A non-base64 character. */ + return (-1); + + switch (state) { + case 0: + if (target) { + if ((size_t)tarindex >= targsize) + return (-1); + target[tarindex] = (pos - Base64) << 2; + } + state = 1; + break; + case 1: + if (target) { + if ((size_t)tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 4; + target[tarindex+1] = ((pos - Base64) & 0x0f) + << 4 ; + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + if ((size_t)tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 2; + target[tarindex+1] = ((pos - Base64) & 0x03) + << 6; + } + tarindex++; + state = 3; + break; + case 3: + if (target) { + if ((size_t)tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64); + } + tarindex++; + state = 0; + break; + default: + abort(); + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /*%< We got a pad char. */ + ch = *src++; /*%< Skip it, get next. */ + switch (state) { + case 0: /*%< Invalid = in first position */ + case 1: /*%< Invalid = in second position */ + return (-1); + + case 2: /*%< Valid, means one byte of info */ + /* Skip any number of spaces. */ + for ((void)NULL; ch != '\0'; ch = *src++) + if (!isspace(ch)) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = *src++; /*%< Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /*%< Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for ((void)NULL; ch != '\0'; ch = *src++) + if (!isspace(ch)) + return (-1); + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target && target[tarindex] != 0) + return (-1); + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return (-1); + } + + return (tarindex); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/isc/bitncmp.c b/contrib/bind-9.5.2/lib/bind/isc/bitncmp.c new file mode 100644 index 0000000000..6addf1f6e4 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/bitncmp.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: bitncmp.c,v 1.3.672.1 2008/09/26 06:30:52 marka Exp $"; +#endif + +#include "port_before.h" + +#include + +#include + +#include "port_after.h" + +#include + +/*% + * int + * bitncmp(l, r, n) + * compare bit masks l and r, for n bits. + * return: + * -1, 1, or 0 in the libc tradition. + * note: + * network byte order assumed. this means 192.5.5.240/28 has + * 0x11110000 in its fourth octet. + * author: + * Paul Vixie (ISC), June 1996 + */ +int +bitncmp(const void *l, const void *r, int n) { + u_int lb, rb; + int x, b; + + b = n / 8; + x = memcmp(l, r, b); + if (x || (n % 8) == 0) + return (x); + + lb = ((const u_char *)l)[b]; + rb = ((const u_char *)r)[b]; + for (b = n % 8; b > 0; b--) { + if ((lb & 0x80) != (rb & 0x80)) { + if (lb & 0x80) + return (1); + return (-1); + } + lb <<= 1; + rb <<= 1; + } + return (0); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/isc/bitncmp.mdoc b/contrib/bind-9.5.2/lib/bind/isc/bitncmp.mdoc new file mode 100644 index 0000000000..7d4646c3fc --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/bitncmp.mdoc @@ -0,0 +1,82 @@ +.\" $Id: bitncmp.mdoc,v 1.3 2004/03/09 06:30:07 marka Exp $ +.\" +.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (c) 1996,1999 by Internet Software Consortium. +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND 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. +.\" +.Dd June 1, 1996 +.Dt BITNCMP 3 +.Os BSD 4 +.Sh NAME +.Nm bitncmp +.Nd compare bit masks +.Sh SYNOPSIS +.Ft int +.Fn bitncmp "const void *l" "const void *r" "int n" +.Sh DESCRIPTION +The function +.Fn bitncmp +compares the +.Dq Fa n +most-significant bits of the two masks pointed to by +.Dq Fa l +and +.Dq Fa r , +and returns an integer less than, equal to, or greater than 0, according to +whether or not +.Dq Fa l +is lexicographically less than, equal to, or greater than +.Dq Fa r +when taken to be unsigned characters (this behaviour is just like that of +.Xr memcmp 3 ) . +.Pp +.Sy NOTE : +.Fn Bitncmp +assumes +.Sy network byte order ; +this means that the fourth octet of +.Li 192.5.5.240/28 +.Li 0x11110000 . +.Sh RETURN VALUES +.Fn Bitncmp +returns values in the manner of +.Xr memcmp 3 : +.Bd -ragged -offset indent ++1 if +.Dq Fa 1 +is greater than +.Dq Fa r ; +.Pp +-1 if +.Dq Fa l +is less than +.Dq Fa r ; +and +.Pp +0 if +.Dq Fa l +is equal to +.Dq Fa r , +.Ed +.Pp +where +.Dq Fa l +and +.Dq Fa r +are both interpreted as strings of unsigned characters (through bit +.Dq Fa n . ) +.Sh SEE ALSO +.Xr memcmp 3 . +.Sh AUTHOR +Paul Vixie (ISC). diff --git a/contrib/bind-9.5.2/lib/bind/isc/ctl_clnt.c b/contrib/bind-9.5.2/lib/bind/isc/ctl_clnt.c new file mode 100644 index 0000000000..cc8ee2f9d6 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/ctl_clnt.c @@ -0,0 +1,620 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: ctl_clnt.c,v 1.9.140.1 2008/02/18 04:10:16 marka Exp $"; +#endif /* not lint */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1998,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +/* Extern. */ + +#include "port_before.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_MEMORY_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "ctl_p.h" + +#include "port_after.h" + +/* Constants. */ + + +/* Macros. */ + +#define donefunc_p(ctx) ((ctx).donefunc != NULL) +#define arpacode_p(line) (isdigit((unsigned char)(line[0])) && \ + isdigit((unsigned char)(line[1])) && \ + isdigit((unsigned char)(line[2]))) +#define arpacont_p(line) (line[3] == '-') +#define arpadone_p(line) (line[3] == ' ' || line[3] == '\t' || \ + line[3] == '\r' || line[3] == '\0') + +/* Types. */ + +enum state { + initializing = 0, connecting, connected, destroyed +}; + +struct ctl_tran { + LINK(struct ctl_tran) link; + LINK(struct ctl_tran) wlink; + struct ctl_cctx * ctx; + struct ctl_buf outbuf; + ctl_clntdone donefunc; + void * uap; +}; + +struct ctl_cctx { + enum state state; + evContext ev; + int sock; + ctl_logfunc logger; + ctl_clntdone donefunc; + void * uap; + evConnID coID; + evTimerID tiID; + evFileID rdID; + evStreamID wrID; + struct ctl_buf inbuf; + struct timespec timeout; + LIST(struct ctl_tran) tran; + LIST(struct ctl_tran) wtran; +}; + +/* Forward. */ + +static struct ctl_tran *new_tran(struct ctl_cctx *, ctl_clntdone, void *, int); +static void start_write(struct ctl_cctx *); +static void destroy(struct ctl_cctx *, int); +static void error(struct ctl_cctx *); +static void new_state(struct ctl_cctx *, enum state); +static void conn_done(evContext, void *, int, + const void *, int, + const void *, int); +static void write_done(evContext, void *, int, int); +static void start_read(struct ctl_cctx *); +static void stop_read(struct ctl_cctx *); +static void readable(evContext, void *, int, int); +static void start_timer(struct ctl_cctx *); +static void stop_timer(struct ctl_cctx *); +static void touch_timer(struct ctl_cctx *); +static void timer(evContext, void *, + struct timespec, struct timespec); + +#ifndef HAVE_MEMCHR +static void * +memchr(const void *b, int c, size_t len) { + const unsigned char *p = b; + size_t i; + + for (i = 0; i < len; i++, p++) + if (*p == (unsigned char)c) + return ((void *)p); + return (NULL); +} +#endif + +/* Private data. */ + +static const char * const state_names[] = { + "initializing", "connecting", "connected", "destroyed" +}; + +/* Public. */ + +/*% + * void + * ctl_client() + * create, condition, and connect to a listener on the control port. + */ +struct ctl_cctx * +ctl_client(evContext lev, const struct sockaddr *cap, size_t cap_len, + const struct sockaddr *sap, size_t sap_len, + ctl_clntdone donefunc, void *uap, + u_int timeout, ctl_logfunc logger) +{ + static const char me[] = "ctl_client"; + static const int on = 1; + struct ctl_cctx *ctx; + struct sockaddr *captmp; + + if (logger == NULL) + logger = ctl_logger; + ctx = memget(sizeof *ctx); + if (ctx == NULL) { + (*logger)(ctl_error, "%s: getmem: %s", me, strerror(errno)); + goto fatal; + } + ctx->state = initializing; + ctx->ev = lev; + ctx->logger = logger; + ctx->timeout = evConsTime(timeout, 0); + ctx->donefunc = donefunc; + ctx->uap = uap; + ctx->coID.opaque = NULL; + ctx->tiID.opaque = NULL; + ctx->rdID.opaque = NULL; + ctx->wrID.opaque = NULL; + buffer_init(ctx->inbuf); + INIT_LIST(ctx->tran); + INIT_LIST(ctx->wtran); + ctx->sock = socket(sap->sa_family, SOCK_STREAM, PF_UNSPEC); + if (ctx->sock > evHighestFD(ctx->ev)) { + ctx->sock = -1; + errno = ENOTSOCK; + } + if (ctx->sock < 0) { + (*ctx->logger)(ctl_error, "%s: socket: %s", + me, strerror(errno)); + goto fatal; + } + if (cap != NULL) { + if (setsockopt(ctx->sock, SOL_SOCKET, SO_REUSEADDR, + (const char *)&on, sizeof on) != 0) { + (*ctx->logger)(ctl_warning, + "%s: setsockopt(REUSEADDR): %s", + me, strerror(errno)); + } + DE_CONST(cap, captmp); + if (bind(ctx->sock, captmp, cap_len) < 0) { + (*ctx->logger)(ctl_error, "%s: bind: %s", me, + strerror(errno)); + goto fatal; + } + } + if (evConnect(lev, ctx->sock, (const struct sockaddr *)sap, sap_len, + conn_done, ctx, &ctx->coID) < 0) { + (*ctx->logger)(ctl_error, "%s: evConnect(fd %d): %s", + me, ctx->sock, strerror(errno)); + fatal: + if (ctx != NULL) { + if (ctx->sock >= 0) + close(ctx->sock); + memput(ctx, sizeof *ctx); + } + return (NULL); + } + new_state(ctx, connecting); + return (ctx); +} + +/*% + * void + * ctl_endclient(ctx) + * close a client and release all of its resources. + */ +void +ctl_endclient(struct ctl_cctx *ctx) { + if (ctx->state != destroyed) + destroy(ctx, 0); + memput(ctx, sizeof *ctx); +} + +/*% + * int + * ctl_command(ctx, cmd, len, donefunc, uap) + * Queue a transaction, which will begin with sending cmd + * and complete by calling donefunc with the answer. + */ +int +ctl_command(struct ctl_cctx *ctx, const char *cmd, size_t len, + ctl_clntdone donefunc, void *uap) +{ + struct ctl_tran *tran; + char *pc; + unsigned int n; + + switch (ctx->state) { + case destroyed: + errno = ENOTCONN; + return (-1); + case connecting: + case connected: + break; + default: + abort(); + } + if (len >= (size_t)MAX_LINELEN) { + errno = EMSGSIZE; + return (-1); + } + tran = new_tran(ctx, donefunc, uap, 1); + if (tran == NULL) + return (-1); + if (ctl_bufget(&tran->outbuf, ctx->logger) < 0) + return (-1); + memcpy(tran->outbuf.text, cmd, len); + tran->outbuf.used = len; + for (pc = tran->outbuf.text, n = 0; n < tran->outbuf.used; pc++, n++) + if (!isascii((unsigned char)*pc) || + !isprint((unsigned char)*pc)) + *pc = '\040'; + start_write(ctx); + return (0); +} + +/* Private. */ + +static struct ctl_tran * +new_tran(struct ctl_cctx *ctx, ctl_clntdone donefunc, void *uap, int w) { + struct ctl_tran *new = memget(sizeof *new); + + if (new == NULL) + return (NULL); + new->ctx = ctx; + buffer_init(new->outbuf); + new->donefunc = donefunc; + new->uap = uap; + INIT_LINK(new, link); + INIT_LINK(new, wlink); + APPEND(ctx->tran, new, link); + if (w) + APPEND(ctx->wtran, new, wlink); + return (new); +} + +static void +start_write(struct ctl_cctx *ctx) { + static const char me[] = "isc/ctl_clnt::start_write"; + struct ctl_tran *tran; + struct iovec iov[2], *iovp = iov; + char * tmp; + + REQUIRE(ctx->state == connecting || ctx->state == connected); + /* If there is a write in progress, don't try to write more yet. */ + if (ctx->wrID.opaque != NULL) + return; + /* If there are no trans, make sure timer is off, and we're done. */ + if (EMPTY(ctx->wtran)) { + if (ctx->tiID.opaque != NULL) + stop_timer(ctx); + return; + } + /* Pull it off the head of the write queue. */ + tran = HEAD(ctx->wtran); + UNLINK(ctx->wtran, tran, wlink); + /* Since there are some trans, make sure timer is successfully "on". */ + if (ctx->tiID.opaque != NULL) + touch_timer(ctx); + else + start_timer(ctx); + if (ctx->state == destroyed) + return; + /* Marshall a newline-terminated message and clock it out. */ + *iovp++ = evConsIovec(tran->outbuf.text, tran->outbuf.used); + DE_CONST("\r\n", tmp); + *iovp++ = evConsIovec(tmp, 2); + if (evWrite(ctx->ev, ctx->sock, iov, iovp - iov, + write_done, tran, &ctx->wrID) < 0) { + (*ctx->logger)(ctl_error, "%s: evWrite: %s", me, + strerror(errno)); + error(ctx); + return; + } + if (evTimeRW(ctx->ev, ctx->wrID, ctx->tiID) < 0) { + (*ctx->logger)(ctl_error, "%s: evTimeRW: %s", me, + strerror(errno)); + error(ctx); + return; + } +} + +static void +destroy(struct ctl_cctx *ctx, int notify) { + struct ctl_tran *this, *next; + + if (ctx->sock != -1) { + (void) close(ctx->sock); + ctx->sock = -1; + } + switch (ctx->state) { + case connecting: + REQUIRE(ctx->wrID.opaque == NULL); + REQUIRE(EMPTY(ctx->tran)); + /* + * This test is nec'y since destroy() can be called from + * start_read() while the state is still "connecting". + */ + if (ctx->coID.opaque != NULL) { + (void)evCancelConn(ctx->ev, ctx->coID); + ctx->coID.opaque = NULL; + } + break; + case connected: + REQUIRE(ctx->coID.opaque == NULL); + if (ctx->wrID.opaque != NULL) { + (void)evCancelRW(ctx->ev, ctx->wrID); + ctx->wrID.opaque = NULL; + } + if (ctx->rdID.opaque != NULL) + stop_read(ctx); + break; + case destroyed: + break; + default: + abort(); + } + if (allocated_p(ctx->inbuf)) + ctl_bufput(&ctx->inbuf); + for (this = HEAD(ctx->tran); this != NULL; this = next) { + next = NEXT(this, link); + if (allocated_p(this->outbuf)) + ctl_bufput(&this->outbuf); + if (notify && this->donefunc != NULL) + (*this->donefunc)(ctx, this->uap, NULL, 0); + memput(this, sizeof *this); + } + if (ctx->tiID.opaque != NULL) + stop_timer(ctx); + new_state(ctx, destroyed); +} + +static void +error(struct ctl_cctx *ctx) { + REQUIRE(ctx->state != destroyed); + destroy(ctx, 1); +} + +static void +new_state(struct ctl_cctx *ctx, enum state new_state) { + static const char me[] = "isc/ctl_clnt::new_state"; + + (*ctx->logger)(ctl_debug, "%s: %s -> %s", me, + state_names[ctx->state], state_names[new_state]); + ctx->state = new_state; +} + +static void +conn_done(evContext ev, void *uap, int fd, + const void *la, int lalen, + const void *ra, int ralen) +{ + static const char me[] = "isc/ctl_clnt::conn_done"; + struct ctl_cctx *ctx = uap; + struct ctl_tran *tran; + + UNUSED(ev); + UNUSED(la); + UNUSED(lalen); + UNUSED(ra); + UNUSED(ralen); + + ctx->coID.opaque = NULL; + if (fd < 0) { + (*ctx->logger)(ctl_error, "%s: evConnect: %s", me, + strerror(errno)); + error(ctx); + return; + } + new_state(ctx, connected); + tran = new_tran(ctx, ctx->donefunc, ctx->uap, 0); + if (tran == NULL) { + (*ctx->logger)(ctl_error, "%s: new_tran failed: %s", me, + strerror(errno)); + error(ctx); + return; + } + start_read(ctx); + if (ctx->state == destroyed) { + (*ctx->logger)(ctl_error, "%s: start_read failed: %s", + me, strerror(errno)); + error(ctx); + return; + } +} + +static void +write_done(evContext lev, void *uap, int fd, int bytes) { + struct ctl_tran *tran = (struct ctl_tran *)uap; + struct ctl_cctx *ctx = tran->ctx; + + UNUSED(lev); + UNUSED(fd); + + ctx->wrID.opaque = NULL; + if (ctx->tiID.opaque != NULL) + touch_timer(ctx); + ctl_bufput(&tran->outbuf); + start_write(ctx); + if (bytes < 0) + destroy(ctx, 1); + else + start_read(ctx); +} + +static void +start_read(struct ctl_cctx *ctx) { + static const char me[] = "isc/ctl_clnt::start_read"; + + REQUIRE(ctx->state == connecting || ctx->state == connected); + REQUIRE(ctx->rdID.opaque == NULL); + if (evSelectFD(ctx->ev, ctx->sock, EV_READ, readable, ctx, + &ctx->rdID) < 0) + { + (*ctx->logger)(ctl_error, "%s: evSelect(fd %d): %s", me, + ctx->sock, strerror(errno)); + error(ctx); + return; + } +} + +static void +stop_read(struct ctl_cctx *ctx) { + REQUIRE(ctx->coID.opaque == NULL); + REQUIRE(ctx->rdID.opaque != NULL); + (void)evDeselectFD(ctx->ev, ctx->rdID); + ctx->rdID.opaque = NULL; +} + +static void +readable(evContext ev, void *uap, int fd, int evmask) { + static const char me[] = "isc/ctl_clnt::readable"; + struct ctl_cctx *ctx = uap; + struct ctl_tran *tran; + ssize_t n; + char *eos; + + UNUSED(ev); + + REQUIRE(ctx != NULL); + REQUIRE(fd >= 0); + REQUIRE(evmask == EV_READ); + REQUIRE(ctx->state == connected); + REQUIRE(!EMPTY(ctx->tran)); + tran = HEAD(ctx->tran); + if (!allocated_p(ctx->inbuf) && + ctl_bufget(&ctx->inbuf, ctx->logger) < 0) { + (*ctx->logger)(ctl_error, "%s: can't get an input buffer", me); + error(ctx); + return; + } + n = read(ctx->sock, ctx->inbuf.text + ctx->inbuf.used, + MAX_LINELEN - ctx->inbuf.used); + if (n <= 0) { + (*ctx->logger)(ctl_warning, "%s: read: %s", me, + (n == 0) ? "Unexpected EOF" : strerror(errno)); + error(ctx); + return; + } + if (ctx->tiID.opaque != NULL) + touch_timer(ctx); + ctx->inbuf.used += n; + (*ctx->logger)(ctl_debug, "%s: read %d, used %d", me, + n, ctx->inbuf.used); + again: + eos = memchr(ctx->inbuf.text, '\n', ctx->inbuf.used); + if (eos != NULL && eos != ctx->inbuf.text && eos[-1] == '\r') { + int done = 0; + + eos[-1] = '\0'; + if (!arpacode_p(ctx->inbuf.text)) { + /* XXX Doesn't FTP do this sometimes? Is it legal? */ + (*ctx->logger)(ctl_error, "%s: no arpa code (%s)", me, + ctx->inbuf.text); + error(ctx); + return; + } + if (arpadone_p(ctx->inbuf.text)) + done = 1; + else if (arpacont_p(ctx->inbuf.text)) + done = 0; + else { + /* XXX Doesn't FTP do this sometimes? Is it legal? */ + (*ctx->logger)(ctl_error, "%s: no arpa flag (%s)", me, + ctx->inbuf.text); + error(ctx); + return; + } + (*tran->donefunc)(ctx, tran->uap, ctx->inbuf.text, + (done ? 0 : CTL_MORE)); + ctx->inbuf.used -= ((eos - ctx->inbuf.text) + 1); + if (ctx->inbuf.used == 0U) + ctl_bufput(&ctx->inbuf); + else + memmove(ctx->inbuf.text, eos + 1, ctx->inbuf.used); + if (done) { + UNLINK(ctx->tran, tran, link); + memput(tran, sizeof *tran); + stop_read(ctx); + start_write(ctx); + return; + } + if (allocated_p(ctx->inbuf)) + goto again; + return; + } + if (ctx->inbuf.used == (size_t)MAX_LINELEN) { + (*ctx->logger)(ctl_error, "%s: line too long (%-10s...)", me, + ctx->inbuf.text); + error(ctx); + } +} + +/* Timer related stuff. */ + +static void +start_timer(struct ctl_cctx *ctx) { + static const char me[] = "isc/ctl_clnt::start_timer"; + + REQUIRE(ctx->tiID.opaque == NULL); + if (evSetIdleTimer(ctx->ev, timer, ctx, ctx->timeout, &ctx->tiID) < 0){ + (*ctx->logger)(ctl_error, "%s: evSetIdleTimer: %s", me, + strerror(errno)); + error(ctx); + return; + } +} + +static void +stop_timer(struct ctl_cctx *ctx) { + static const char me[] = "isc/ctl_clnt::stop_timer"; + + REQUIRE(ctx->tiID.opaque != NULL); + if (evClearIdleTimer(ctx->ev, ctx->tiID) < 0) { + (*ctx->logger)(ctl_error, "%s: evClearIdleTimer: %s", me, + strerror(errno)); + error(ctx); + return; + } + ctx->tiID.opaque = NULL; +} + +static void +touch_timer(struct ctl_cctx *ctx) { + REQUIRE(ctx->tiID.opaque != NULL); + + evTouchIdleTimer(ctx->ev, ctx->tiID); +} + +static void +timer(evContext ev, void *uap, struct timespec due, struct timespec itv) { + static const char me[] = "isc/ctl_clnt::timer"; + struct ctl_cctx *ctx = uap; + + UNUSED(ev); + UNUSED(due); + UNUSED(itv); + + ctx->tiID.opaque = NULL; + (*ctx->logger)(ctl_error, "%s: timeout after %u seconds while %s", me, + ctx->timeout.tv_sec, state_names[ctx->state]); + error(ctx); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/isc/ctl_p.c b/contrib/bind-9.5.2/lib/bind/isc/ctl_p.c new file mode 100644 index 0000000000..7ab719a5e6 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/ctl_p.c @@ -0,0 +1,188 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: ctl_p.c,v 1.4 2005/04/27 04:56:35 sra Exp $"; +#endif /* not lint */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1998,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +/* Extern. */ + +#include "port_before.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ctl_p.h" + +#include "port_after.h" + +/* Constants. */ + +const char * const ctl_sevnames[] = { + "debug", "warning", "error" +}; + +/* Public. */ + +/*% + * ctl_logger() + * if ctl_startup()'s caller didn't specify a logger, this one + * is used. this pollutes stderr with all kinds of trash so it will + * probably never be used in real applications. + */ +void +ctl_logger(enum ctl_severity severity, const char *format, ...) { + va_list ap; + static const char me[] = "ctl_logger"; + + fprintf(stderr, "%s(%s): ", me, ctl_sevnames[severity]); + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + fputc('\n', stderr); +} + +int +ctl_bufget(struct ctl_buf *buf, ctl_logfunc logger) { + static const char me[] = "ctl_bufget"; + + REQUIRE(!allocated_p(*buf) && buf->used == 0U); + buf->text = memget(MAX_LINELEN); + if (!allocated_p(*buf)) { + (*logger)(ctl_error, "%s: getmem: %s", me, strerror(errno)); + return (-1); + } + buf->used = 0; + return (0); +} + +void +ctl_bufput(struct ctl_buf *buf) { + + REQUIRE(allocated_p(*buf)); + memput(buf->text, MAX_LINELEN); + buf->text = NULL; + buf->used = 0; +} + +const char * +ctl_sa_ntop(const struct sockaddr *sa, + char *buf, size_t size, + ctl_logfunc logger) +{ + static const char me[] = "ctl_sa_ntop"; + static const char punt[] = "[0].-1"; + char tmp[INET6_ADDRSTRLEN]; + + switch (sa->sa_family) { + case AF_INET6: { + const struct sockaddr_in6 *in6 = + (const struct sockaddr_in6 *) sa; + + if (inet_ntop(in6->sin6_family, &in6->sin6_addr, tmp, sizeof tmp) + == NULL) { + (*logger)(ctl_error, "%s: inet_ntop(%u %04x): %s", + me, in6->sin6_family, + in6->sin6_port, strerror(errno)); + return (punt); + } + if (strlen(tmp) + sizeof "[].65535" > size) { + (*logger)(ctl_error, "%s: buffer overflow", me); + return (punt); + } + (void) sprintf(buf, "[%s].%u", tmp, ntohs(in6->sin6_port)); + return (buf); + } + case AF_INET: { + const struct sockaddr_in *in = + (const struct sockaddr_in *) sa; + + if (inet_ntop(in->sin_family, &in->sin_addr, tmp, sizeof tmp) + == NULL) { + (*logger)(ctl_error, "%s: inet_ntop(%u %04x %08x): %s", + me, in->sin_family, + in->sin_port, in->sin_addr.s_addr, + strerror(errno)); + return (punt); + } + if (strlen(tmp) + sizeof "[].65535" > size) { + (*logger)(ctl_error, "%s: buffer overflow", me); + return (punt); + } + (void) sprintf(buf, "[%s].%u", tmp, ntohs(in->sin_port)); + return (buf); + } +#ifndef NO_SOCKADDR_UN + case AF_UNIX: { + const struct sockaddr_un *un = + (const struct sockaddr_un *) sa; + unsigned int x = sizeof un->sun_path; + + if (x > size) + x = size; + strncpy(buf, un->sun_path, x - 1); + buf[x - 1] = '\0'; + return (buf); + } +#endif + default: + return (punt); + } +} + +void +ctl_sa_copy(const struct sockaddr *src, struct sockaddr *dst) { + switch (src->sa_family) { + case AF_INET6: + *((struct sockaddr_in6 *)dst) = + *((const struct sockaddr_in6 *)src); + break; + case AF_INET: + *((struct sockaddr_in *)dst) = + *((const struct sockaddr_in *)src); + break; +#ifndef NO_SOCKADDR_UN + case AF_UNIX: + *((struct sockaddr_un *)dst) = + *((const struct sockaddr_un *)src); + break; +#endif + default: + *dst = *src; + break; + } +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/isc/ctl_p.h b/contrib/bind-9.5.2/lib/bind/isc/ctl_p.h new file mode 100644 index 0000000000..18a52ae39c --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/ctl_p.h @@ -0,0 +1,28 @@ +struct ctl_buf { + char * text; + size_t used; +}; + +#define MAX_LINELEN 990 /*%< Like SMTP. */ +#ifndef NO_SOCKADDR_UN +#define MAX_NTOP PATH_MAX +#else +#define MAX_NTOP (sizeof "[255.255.255.255].65535") +#endif + +#define allocated_p(Buf) ((Buf).text != NULL) +#define buffer_init(Buf) ((Buf).text = 0, (Buf.used) = 0) + +#define ctl_bufget __ctl_bufget +#define ctl_bufput __ctl_bufput +#define ctl_sa_ntop __ctl_sa_ntop +#define ctl_sa_copy __ctl_sa_copy + +int ctl_bufget(struct ctl_buf *, ctl_logfunc); +void ctl_bufput(struct ctl_buf *); +const char * ctl_sa_ntop(const struct sockaddr *, char *, size_t, + ctl_logfunc); +void ctl_sa_copy(const struct sockaddr *, + struct sockaddr *); + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/isc/ctl_srvr.c b/contrib/bind-9.5.2/lib/bind/isc/ctl_srvr.c new file mode 100644 index 0000000000..919dec7c72 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/ctl_srvr.c @@ -0,0 +1,787 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: ctl_srvr.c,v 1.8.246.1 2008/02/18 04:10:16 marka Exp $"; +#endif /* not lint */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1998,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +/* Extern. */ + +#include "port_before.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_MEMORY_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "ctl_p.h" + +#include "port_after.h" + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +/* Macros. */ + +#define lastverb_p(verb) (verb->name == NULL || verb->func == NULL) +#define address_expr ctl_sa_ntop((struct sockaddr *)&sess->sa, \ + tmp, sizeof tmp, ctx->logger) + +/* Types. */ + +enum state { + available = 0, initializing, writing, reading, reading_data, + processing, idling, quitting, closing +}; + +union sa_un { + struct sockaddr_in in; +#ifndef NO_SOCKADDR_UN + struct sockaddr_un un; +#endif +}; + +struct ctl_sess { + LINK(struct ctl_sess) link; + struct ctl_sctx * ctx; + enum state state; + int sock; + union sa_un sa; + evFileID rdID; + evStreamID wrID; + evTimerID rdtiID; + evTimerID wrtiID; + struct ctl_buf inbuf; + struct ctl_buf outbuf; + const struct ctl_verb * verb; + u_int helpcode; + const void * respctx; + u_int respflags; + ctl_srvrdone donefunc; + void * uap; + void * csctx; +}; + +struct ctl_sctx { + evContext ev; + void * uctx; + u_int unkncode; + u_int timeoutcode; + const struct ctl_verb * verbs; + const struct ctl_verb * connverb; + int sock; + int max_sess; + int cur_sess; + struct timespec timeout; + ctl_logfunc logger; + evConnID acID; + LIST(struct ctl_sess) sess; +}; + +/* Forward. */ + +static void ctl_accept(evContext, void *, int, + const void *, int, + const void *, int); +static void ctl_close(struct ctl_sess *); +static void ctl_new_state(struct ctl_sess *, + enum state, + const char *); +static void ctl_start_read(struct ctl_sess *); +static void ctl_stop_read(struct ctl_sess *); +static void ctl_readable(evContext, void *, int, int); +static void ctl_rdtimeout(evContext, void *, + struct timespec, + struct timespec); +static void ctl_wrtimeout(evContext, void *, + struct timespec, + struct timespec); +static void ctl_docommand(struct ctl_sess *); +static void ctl_writedone(evContext, void *, int, int); +static void ctl_morehelp(struct ctl_sctx *, + struct ctl_sess *, + const struct ctl_verb *, + const char *, + u_int, const void *, void *); +static void ctl_signal_done(struct ctl_sctx *, + struct ctl_sess *); + +/* Private data. */ + +static const char * state_names[] = { + "available", "initializing", "writing", "reading", + "reading_data", "processing", "idling", "quitting", "closing" +}; + +static const char space[] = " "; + +static const struct ctl_verb fakehelpverb = { + "fakehelp", ctl_morehelp , NULL +}; + +/* Public. */ + +/*% + * void + * ctl_server() + * create, condition, and start a listener on the control port. + */ +struct ctl_sctx * +ctl_server(evContext lev, const struct sockaddr *sap, size_t sap_len, + const struct ctl_verb *verbs, + u_int unkncode, u_int timeoutcode, + u_int timeout, int backlog, int max_sess, + ctl_logfunc logger, void *uctx) +{ + static const char me[] = "ctl_server"; + static const int on = 1; + const struct ctl_verb *connverb; + struct ctl_sctx *ctx; + int save_errno; + + if (logger == NULL) + logger = ctl_logger; + for (connverb = verbs; + connverb->name != NULL && connverb->func != NULL; + connverb++) + if (connverb->name[0] == '\0') + break; + if (connverb->func == NULL) { + (*logger)(ctl_error, "%s: no connection verb found", me); + return (NULL); + } + ctx = memget(sizeof *ctx); + if (ctx == NULL) { + (*logger)(ctl_error, "%s: getmem: %s", me, strerror(errno)); + return (NULL); + } + ctx->ev = lev; + ctx->uctx = uctx; + ctx->unkncode = unkncode; + ctx->timeoutcode = timeoutcode; + ctx->verbs = verbs; + ctx->timeout = evConsTime(timeout, 0); + ctx->logger = logger; + ctx->connverb = connverb; + ctx->max_sess = max_sess; + ctx->cur_sess = 0; + INIT_LIST(ctx->sess); + ctx->sock = socket(sap->sa_family, SOCK_STREAM, PF_UNSPEC); + if (ctx->sock > evHighestFD(ctx->ev)) { + ctx->sock = -1; + errno = ENOTSOCK; + } + if (ctx->sock < 0) { + save_errno = errno; + (*ctx->logger)(ctl_error, "%s: socket: %s", + me, strerror(errno)); + memput(ctx, sizeof *ctx); + errno = save_errno; + return (NULL); + } + if (ctx->sock > evHighestFD(lev)) { + close(ctx->sock); + (*ctx->logger)(ctl_error, "%s: file descriptor > evHighestFD"); + errno = ENFILE; + memput(ctx, sizeof *ctx); + return (NULL); + } +#ifdef NO_UNIX_REUSEADDR + if (sap->sa_family != AF_UNIX) +#endif + if (setsockopt(ctx->sock, SOL_SOCKET, SO_REUSEADDR, + (const char *)&on, sizeof on) != 0) { + (*ctx->logger)(ctl_warning, + "%s: setsockopt(REUSEADDR): %s", + me, strerror(errno)); + } + if (bind(ctx->sock, sap, sap_len) < 0) { + char tmp[MAX_NTOP]; + save_errno = errno; + (*ctx->logger)(ctl_error, "%s: bind: %s: %s", + me, ctl_sa_ntop((const struct sockaddr *)sap, + tmp, sizeof tmp, ctx->logger), + strerror(save_errno)); + close(ctx->sock); + memput(ctx, sizeof *ctx); + errno = save_errno; + return (NULL); + } + if (fcntl(ctx->sock, F_SETFD, 1) < 0) { + (*ctx->logger)(ctl_warning, "%s: fcntl: %s", me, + strerror(errno)); + } + if (evListen(lev, ctx->sock, backlog, ctl_accept, ctx, + &ctx->acID) < 0) { + save_errno = errno; + (*ctx->logger)(ctl_error, "%s: evListen(fd %d): %s", + me, ctx->sock, strerror(errno)); + close(ctx->sock); + memput(ctx, sizeof *ctx); + errno = save_errno; + return (NULL); + } + (*ctx->logger)(ctl_debug, "%s: new ctx %p, sock %d", + me, ctx, ctx->sock); + return (ctx); +} + +/*% + * void + * ctl_endserver(ctx) + * if the control listener is open, close it. clean out all eventlib + * stuff. close all active sessions. + */ +void +ctl_endserver(struct ctl_sctx *ctx) { + static const char me[] = "ctl_endserver"; + struct ctl_sess *this, *next; + + (*ctx->logger)(ctl_debug, "%s: ctx %p, sock %d, acID %p, sess %p", + me, ctx, ctx->sock, ctx->acID.opaque, ctx->sess); + if (ctx->acID.opaque != NULL) { + (void)evCancelConn(ctx->ev, ctx->acID); + ctx->acID.opaque = NULL; + } + if (ctx->sock != -1) { + (void) close(ctx->sock); + ctx->sock = -1; + } + for (this = HEAD(ctx->sess); this != NULL; this = next) { + next = NEXT(this, link); + ctl_close(this); + } + memput(ctx, sizeof *ctx); +} + +/*% + * If body is non-NULL then it we add a "." line after it. + * Caller must have escaped lines with leading ".". + */ +void +ctl_response(struct ctl_sess *sess, u_int code, const char *text, + u_int flags, const void *respctx, ctl_srvrdone donefunc, + void *uap, const char *body, size_t bodylen) +{ + static const char me[] = "ctl_response"; + struct iovec iov[3], *iovp = iov; + struct ctl_sctx *ctx = sess->ctx; + char tmp[MAX_NTOP], *pc; + int n; + + REQUIRE(sess->state == initializing || + sess->state == processing || + sess->state == reading_data || + sess->state == writing); + REQUIRE(sess->wrtiID.opaque == NULL); + REQUIRE(sess->wrID.opaque == NULL); + ctl_new_state(sess, writing, me); + sess->donefunc = donefunc; + sess->uap = uap; + if (!allocated_p(sess->outbuf) && + ctl_bufget(&sess->outbuf, ctx->logger) < 0) { + (*ctx->logger)(ctl_error, "%s: %s: cant get an output buffer", + me, address_expr); + goto untimely; + } + if (sizeof "000-\r\n" + strlen(text) > (size_t)MAX_LINELEN) { + (*ctx->logger)(ctl_error, "%s: %s: output buffer ovf, closing", + me, address_expr); + goto untimely; + } + sess->outbuf.used = SPRINTF((sess->outbuf.text, "%03d%c%s\r\n", + code, (flags & CTL_MORE) != 0 ? '-' : ' ', + text)); + for (pc = sess->outbuf.text, n = 0; + n < (int)sess->outbuf.used-2; pc++, n++) + if (!isascii((unsigned char)*pc) || + !isprint((unsigned char)*pc)) + *pc = '\040'; + *iovp++ = evConsIovec(sess->outbuf.text, sess->outbuf.used); + if (body != NULL) { + char *tmp; + DE_CONST(body, tmp); + *iovp++ = evConsIovec(tmp, bodylen); + DE_CONST(".\r\n", tmp); + *iovp++ = evConsIovec(tmp, 3); + } + (*ctx->logger)(ctl_debug, "%s: [%d] %s", me, + sess->outbuf.used, sess->outbuf.text); + if (evWrite(ctx->ev, sess->sock, iov, iovp - iov, + ctl_writedone, sess, &sess->wrID) < 0) { + (*ctx->logger)(ctl_error, "%s: %s: evWrite: %s", me, + address_expr, strerror(errno)); + goto untimely; + } + if (evSetIdleTimer(ctx->ev, ctl_wrtimeout, sess, ctx->timeout, + &sess->wrtiID) < 0) + { + (*ctx->logger)(ctl_error, "%s: %s: evSetIdleTimer: %s", me, + address_expr, strerror(errno)); + goto untimely; + } + if (evTimeRW(ctx->ev, sess->wrID, sess->wrtiID) < 0) { + (*ctx->logger)(ctl_error, "%s: %s: evTimeRW: %s", me, + address_expr, strerror(errno)); + untimely: + ctl_signal_done(ctx, sess); + ctl_close(sess); + return; + } + sess->respctx = respctx; + sess->respflags = flags; +} + +void +ctl_sendhelp(struct ctl_sess *sess, u_int code) { + static const char me[] = "ctl_sendhelp"; + struct ctl_sctx *ctx = sess->ctx; + + sess->helpcode = code; + sess->verb = &fakehelpverb; + ctl_morehelp(ctx, sess, NULL, me, CTL_MORE, + (const void *)ctx->verbs, NULL); +} + +void * +ctl_getcsctx(struct ctl_sess *sess) { + return (sess->csctx); +} + +void * +ctl_setcsctx(struct ctl_sess *sess, void *csctx) { + void *old = sess->csctx; + + sess->csctx = csctx; + return (old); +} + +/* Private functions. */ + +static void +ctl_accept(evContext lev, void *uap, int fd, + const void *lav, int lalen, + const void *rav, int ralen) +{ + static const char me[] = "ctl_accept"; + struct ctl_sctx *ctx = uap; + struct ctl_sess *sess = NULL; + char tmp[MAX_NTOP]; + + UNUSED(lev); + UNUSED(lalen); + UNUSED(ralen); + + if (fd < 0) { + (*ctx->logger)(ctl_error, "%s: accept: %s", + me, strerror(errno)); + return; + } + if (ctx->cur_sess == ctx->max_sess) { + (*ctx->logger)(ctl_error, "%s: %s: too many control sessions", + me, ctl_sa_ntop((const struct sockaddr *)rav, + tmp, sizeof tmp, + ctx->logger)); + (void) close(fd); + return; + } + sess = memget(sizeof *sess); + if (sess == NULL) { + (*ctx->logger)(ctl_error, "%s: memget: %s", me, + strerror(errno)); + (void) close(fd); + return; + } + if (fcntl(fd, F_SETFD, 1) < 0) { + (*ctx->logger)(ctl_warning, "%s: fcntl: %s", me, + strerror(errno)); + } + ctx->cur_sess++; + INIT_LINK(sess, link); + APPEND(ctx->sess, sess, link); + sess->ctx = ctx; + sess->sock = fd; + sess->wrID.opaque = NULL; + sess->rdID.opaque = NULL; + sess->wrtiID.opaque = NULL; + sess->rdtiID.opaque = NULL; + sess->respctx = NULL; + sess->csctx = NULL; + if (((const struct sockaddr *)rav)->sa_family == AF_UNIX) + ctl_sa_copy((const struct sockaddr *)lav, + (struct sockaddr *)&sess->sa); + else + ctl_sa_copy((const struct sockaddr *)rav, + (struct sockaddr *)&sess->sa); + sess->donefunc = NULL; + buffer_init(sess->inbuf); + buffer_init(sess->outbuf); + sess->state = available; + ctl_new_state(sess, initializing, me); + sess->verb = ctx->connverb; + (*ctx->logger)(ctl_debug, "%s: %s: accepting (fd %d)", + me, address_expr, sess->sock); + (*ctx->connverb->func)(ctx, sess, ctx->connverb, "", 0, + (const struct sockaddr *)rav, ctx->uctx); +} + +static void +ctl_new_state(struct ctl_sess *sess, enum state new_state, const char *reason) +{ + static const char me[] = "ctl_new_state"; + struct ctl_sctx *ctx = sess->ctx; + char tmp[MAX_NTOP]; + + (*ctx->logger)(ctl_debug, "%s: %s: %s -> %s (%s)", + me, address_expr, + state_names[sess->state], + state_names[new_state], reason); + sess->state = new_state; +} + +static void +ctl_close(struct ctl_sess *sess) { + static const char me[] = "ctl_close"; + struct ctl_sctx *ctx = sess->ctx; + char tmp[MAX_NTOP]; + + REQUIRE(sess->state == initializing || + sess->state == writing || + sess->state == reading || + sess->state == processing || + sess->state == reading_data || + sess->state == idling); + REQUIRE(sess->sock != -1); + if (sess->state == reading || sess->state == reading_data) + ctl_stop_read(sess); + else if (sess->state == writing) { + if (sess->wrID.opaque != NULL) { + (void) evCancelRW(ctx->ev, sess->wrID); + sess->wrID.opaque = NULL; + } + if (sess->wrtiID.opaque != NULL) { + (void) evClearIdleTimer(ctx->ev, sess->wrtiID); + sess->wrtiID.opaque = NULL; + } + } + ctl_new_state(sess, closing, me); + (void) close(sess->sock); + if (allocated_p(sess->inbuf)) + ctl_bufput(&sess->inbuf); + if (allocated_p(sess->outbuf)) + ctl_bufput(&sess->outbuf); + (*ctx->logger)(ctl_debug, "%s: %s: closed (fd %d)", + me, address_expr, sess->sock); + UNLINK(ctx->sess, sess, link); + memput(sess, sizeof *sess); + ctx->cur_sess--; +} + +static void +ctl_start_read(struct ctl_sess *sess) { + static const char me[] = "ctl_start_read"; + struct ctl_sctx *ctx = sess->ctx; + char tmp[MAX_NTOP]; + + REQUIRE(sess->state == initializing || + sess->state == writing || + sess->state == processing || + sess->state == idling); + REQUIRE(sess->rdtiID.opaque == NULL); + REQUIRE(sess->rdID.opaque == NULL); + sess->inbuf.used = 0; + if (evSetIdleTimer(ctx->ev, ctl_rdtimeout, sess, ctx->timeout, + &sess->rdtiID) < 0) + { + (*ctx->logger)(ctl_error, "%s: %s: evSetIdleTimer: %s", me, + address_expr, strerror(errno)); + ctl_close(sess); + return; + } + if (evSelectFD(ctx->ev, sess->sock, EV_READ, + ctl_readable, sess, &sess->rdID) < 0) { + (*ctx->logger)(ctl_error, "%s: %s: evSelectFD: %s", me, + address_expr, strerror(errno)); + return; + } + ctl_new_state(sess, reading, me); +} + +static void +ctl_stop_read(struct ctl_sess *sess) { + static const char me[] = "ctl_stop_read"; + struct ctl_sctx *ctx = sess->ctx; + + REQUIRE(sess->state == reading || sess->state == reading_data); + REQUIRE(sess->rdID.opaque != NULL); + (void) evDeselectFD(ctx->ev, sess->rdID); + sess->rdID.opaque = NULL; + if (sess->rdtiID.opaque != NULL) { + (void) evClearIdleTimer(ctx->ev, sess->rdtiID); + sess->rdtiID.opaque = NULL; + } + ctl_new_state(sess, idling, me); +} + +static void +ctl_readable(evContext lev, void *uap, int fd, int evmask) { + static const char me[] = "ctl_readable"; + struct ctl_sess *sess = uap; + struct ctl_sctx *ctx; + char *eos, tmp[MAX_NTOP]; + ssize_t n; + + REQUIRE(sess != NULL); + REQUIRE(fd >= 0); + REQUIRE(evmask == EV_READ); + REQUIRE(sess->state == reading || sess->state == reading_data); + + ctx = sess->ctx; + evTouchIdleTimer(lev, sess->rdtiID); + if (!allocated_p(sess->inbuf) && + ctl_bufget(&sess->inbuf, ctx->logger) < 0) { + (*ctx->logger)(ctl_error, "%s: %s: cant get an input buffer", + me, address_expr); + ctl_close(sess); + return; + } + n = read(sess->sock, sess->inbuf.text + sess->inbuf.used, + MAX_LINELEN - sess->inbuf.used); + if (n <= 0) { + (*ctx->logger)(ctl_debug, "%s: %s: read: %s", + me, address_expr, + (n == 0) ? "Unexpected EOF" : strerror(errno)); + ctl_close(sess); + return; + } + sess->inbuf.used += n; + eos = memchr(sess->inbuf.text, '\n', sess->inbuf.used); + if (eos != NULL && eos != sess->inbuf.text && eos[-1] == '\r') { + eos[-1] = '\0'; + if ((sess->respflags & CTL_DATA) != 0) { + INSIST(sess->verb != NULL); + (*sess->verb->func)(sess->ctx, sess, sess->verb, + sess->inbuf.text, + CTL_DATA, sess->respctx, + sess->ctx->uctx); + } else { + ctl_stop_read(sess); + ctl_docommand(sess); + } + sess->inbuf.used -= ((eos - sess->inbuf.text) + 1); + if (sess->inbuf.used == 0U) + ctl_bufput(&sess->inbuf); + else + memmove(sess->inbuf.text, eos + 1, sess->inbuf.used); + return; + } + if (sess->inbuf.used == (size_t)MAX_LINELEN) { + (*ctx->logger)(ctl_error, "%s: %s: line too long, closing", + me, address_expr); + ctl_close(sess); + } +} + +static void +ctl_wrtimeout(evContext lev, void *uap, + struct timespec due, + struct timespec itv) +{ + static const char me[] = "ctl_wrtimeout"; + struct ctl_sess *sess = uap; + struct ctl_sctx *ctx = sess->ctx; + char tmp[MAX_NTOP]; + + UNUSED(lev); + UNUSED(due); + UNUSED(itv); + + REQUIRE(sess->state == writing); + sess->wrtiID.opaque = NULL; + (*ctx->logger)(ctl_warning, "%s: %s: write timeout, closing", + me, address_expr); + if (sess->wrID.opaque != NULL) { + (void) evCancelRW(ctx->ev, sess->wrID); + sess->wrID.opaque = NULL; + } + ctl_signal_done(ctx, sess); + ctl_new_state(sess, processing, me); + ctl_close(sess); +} + +static void +ctl_rdtimeout(evContext lev, void *uap, + struct timespec due, + struct timespec itv) +{ + static const char me[] = "ctl_rdtimeout"; + struct ctl_sess *sess = uap; + struct ctl_sctx *ctx = sess->ctx; + char tmp[MAX_NTOP]; + + UNUSED(lev); + UNUSED(due); + UNUSED(itv); + + REQUIRE(sess->state == reading); + sess->rdtiID.opaque = NULL; + (*ctx->logger)(ctl_warning, "%s: %s: timeout, closing", + me, address_expr); + if (sess->state == reading || sess->state == reading_data) + ctl_stop_read(sess); + ctl_signal_done(ctx, sess); + ctl_new_state(sess, processing, me); + ctl_response(sess, ctx->timeoutcode, "Timeout.", CTL_EXIT, NULL, + NULL, NULL, NULL, 0); +} + +static void +ctl_docommand(struct ctl_sess *sess) { + static const char me[] = "ctl_docommand"; + char *name, *rest, tmp[MAX_NTOP]; + struct ctl_sctx *ctx = sess->ctx; + const struct ctl_verb *verb; + + REQUIRE(allocated_p(sess->inbuf)); + (*ctx->logger)(ctl_debug, "%s: %s: \"%s\" [%u]", + me, address_expr, + sess->inbuf.text, (u_int)sess->inbuf.used); + ctl_new_state(sess, processing, me); + name = sess->inbuf.text + strspn(sess->inbuf.text, space); + rest = name + strcspn(name, space); + if (*rest != '\0') { + *rest++ = '\0'; + rest += strspn(rest, space); + } + for (verb = ctx->verbs; + verb != NULL && verb->name != NULL && verb->func != NULL; + verb++) + if (verb->name[0] != '\0' && strcasecmp(name, verb->name) == 0) + break; + if (verb != NULL && verb->name != NULL && verb->func != NULL) { + sess->verb = verb; + (*verb->func)(ctx, sess, verb, rest, 0, NULL, ctx->uctx); + } else { + char buf[1100]; + + if (sizeof "Unrecognized command \"\" (args \"\")" + + strlen(name) + strlen(rest) > sizeof buf) + strcpy(buf, "Unrecognized command (buf ovf)"); + else + sprintf(buf, + "Unrecognized command \"%s\" (args \"%s\")", + name, rest); + ctl_response(sess, ctx->unkncode, buf, 0, NULL, NULL, NULL, + NULL, 0); + } +} + +static void +ctl_writedone(evContext lev, void *uap, int fd, int bytes) { + static const char me[] = "ctl_writedone"; + struct ctl_sess *sess = uap; + struct ctl_sctx *ctx = sess->ctx; + char tmp[MAX_NTOP]; + int save_errno = errno; + + UNUSED(lev); + UNUSED(uap); + + REQUIRE(sess->state == writing); + REQUIRE(fd == sess->sock); + REQUIRE(sess->wrtiID.opaque != NULL); + sess->wrID.opaque = NULL; + (void) evClearIdleTimer(ctx->ev, sess->wrtiID); + sess->wrtiID.opaque = NULL; + if (bytes < 0) { + (*ctx->logger)(ctl_error, "%s: %s: %s", + me, address_expr, strerror(save_errno)); + ctl_close(sess); + return; + } + + INSIST(allocated_p(sess->outbuf)); + ctl_bufput(&sess->outbuf); + if ((sess->respflags & CTL_EXIT) != 0) { + ctl_signal_done(ctx, sess); + ctl_close(sess); + return; + } else if ((sess->respflags & CTL_MORE) != 0) { + INSIST(sess->verb != NULL); + (*sess->verb->func)(sess->ctx, sess, sess->verb, "", + CTL_MORE, sess->respctx, sess->ctx->uctx); + } else { + ctl_signal_done(ctx, sess); + ctl_start_read(sess); + } +} + +static void +ctl_morehelp(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *text, + u_int respflags, const void *respctx, void *uctx) +{ + const struct ctl_verb *this = respctx, *next = this + 1; + + UNUSED(ctx); + UNUSED(verb); + UNUSED(text); + UNUSED(uctx); + + REQUIRE(!lastverb_p(this)); + REQUIRE((respflags & CTL_MORE) != 0); + if (lastverb_p(next)) + respflags &= ~CTL_MORE; + ctl_response(sess, sess->helpcode, this->help, respflags, next, + NULL, NULL, NULL, 0); +} + +static void +ctl_signal_done(struct ctl_sctx *ctx, struct ctl_sess *sess) { + if (sess->donefunc != NULL) { + (*sess->donefunc)(ctx, sess, sess->uap); + sess->donefunc = NULL; + } +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/isc/ev_connects.c b/contrib/bind-9.5.2/lib/bind/isc/ev_connects.c new file mode 100644 index 0000000000..38dfdbe512 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/ev_connects.c @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1995-1999 by Internet Software Consortium + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +/* ev_connects.c - implement asynch connect/accept for the eventlib + * vix 16sep96 [initial] + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: ev_connects.c,v 1.8 2006/03/09 23:57:56 marka Exp $"; +#endif + +/* Import. */ + +#include "port_before.h" +#include "fd_setsize.h" + +#include +#include +#include + +#include + +#include +#include +#include "eventlib_p.h" + +#include "port_after.h" + +/* Macros. */ + +#define GETXXXNAME(f, s, sa, len) ( \ + (f((s), (&sa), (&len)) >= 0) ? 0 : \ + (errno != EAFNOSUPPORT && errno != EOPNOTSUPP) ? -1 : ( \ + memset(&(sa), 0, sizeof (sa)), \ + (len) = sizeof (sa), \ + (sa).sa_family = AF_UNIX, \ + 0 \ + ) \ + ) + +/* Forward. */ + +static void listener(evContext ctx, void *uap, int fd, int evmask); +static void connector(evContext ctx, void *uap, int fd, int evmask); + +/* Public. */ + +int +evListen(evContext opaqueCtx, int fd, int maxconn, + evConnFunc func, void *uap, evConnID *id) +{ + evContext_p *ctx = opaqueCtx.opaque; + evConn *new; + int mode; + + OKNEW(new); + new->flags = EV_CONN_LISTEN; + OKFREE(mode = fcntl(fd, F_GETFL, NULL), new); /*%< side effect: validate fd. */ + /* + * Remember the nonblocking status. We assume that either evSelectFD + * has not been done to this fd, or that if it has then the caller + * will evCancelConn before they evDeselectFD. If our assumptions + * are not met, then we might restore the old nonblocking status + * incorrectly. + */ + if ((mode & PORT_NONBLOCK) == 0) { +#ifdef USE_FIONBIO_IOCTL + int on = 1; + OKFREE(ioctl(fd, FIONBIO, (char *)&on), new); +#else + OKFREE(fcntl(fd, F_SETFL, mode | PORT_NONBLOCK), new); +#endif + new->flags |= EV_CONN_BLOCK; + } + OKFREE(listen(fd, maxconn), new); + if (evSelectFD(opaqueCtx, fd, EV_READ, listener, new, &new->file) < 0){ + int save = errno; + + FREE(new); + errno = save; + return (-1); + } + new->flags |= EV_CONN_SELECTED; + new->func = func; + new->uap = uap; + new->fd = fd; + if (ctx->conns != NULL) + ctx->conns->prev = new; + new->prev = NULL; + new->next = ctx->conns; + ctx->conns = new; + if (id) + id->opaque = new; + return (0); +} + +int +evConnect(evContext opaqueCtx, int fd, const void *ra, int ralen, + evConnFunc func, void *uap, evConnID *id) +{ + evContext_p *ctx = opaqueCtx.opaque; + evConn *new; + + OKNEW(new); + new->flags = 0; + /* Do the select() first to get the socket into nonblocking mode. */ + if (evSelectFD(opaqueCtx, fd, EV_MASK_ALL, + connector, new, &new->file) < 0) { + int save = errno; + + FREE(new); + errno = save; + return (-1); + } + new->flags |= EV_CONN_SELECTED; + if (connect(fd, ra, ralen) < 0 && + errno != EWOULDBLOCK && + errno != EAGAIN && + errno != EINPROGRESS) { + int save = errno; + + (void) evDeselectFD(opaqueCtx, new->file); + FREE(new); + errno = save; + return (-1); + } + /* No error, or EWOULDBLOCK. select() tells when it's ready. */ + new->func = func; + new->uap = uap; + new->fd = fd; + if (ctx->conns != NULL) + ctx->conns->prev = new; + new->prev = NULL; + new->next = ctx->conns; + ctx->conns = new; + if (id) + id->opaque = new; + return (0); +} + +int +evCancelConn(evContext opaqueCtx, evConnID id) { + evContext_p *ctx = opaqueCtx.opaque; + evConn *this = id.opaque; + evAccept *acc, *nxtacc; + int mode; + + if ((this->flags & EV_CONN_SELECTED) != 0) + (void) evDeselectFD(opaqueCtx, this->file); + if ((this->flags & EV_CONN_BLOCK) != 0) { + mode = fcntl(this->fd, F_GETFL, NULL); + if (mode == -1) { + if (errno != EBADF) + return (-1); + } else { +#ifdef USE_FIONBIO_IOCTL + int off = 0; + OK(ioctl(this->fd, FIONBIO, (char *)&off)); +#else + OK(fcntl(this->fd, F_SETFL, mode & ~PORT_NONBLOCK)); +#endif + } + } + + /* Unlink from ctx->conns. */ + if (this->prev != NULL) + this->prev->next = this->next; + else + ctx->conns = this->next; + if (this->next != NULL) + this->next->prev = this->prev; + + /* + * Remove `this' from the ctx->accepts list (zero or more times). + */ + for (acc = HEAD(ctx->accepts), nxtacc = NULL; + acc != NULL; + acc = nxtacc) + { + nxtacc = NEXT(acc, link); + if (acc->conn == this) { + UNLINK(ctx->accepts, acc, link); + close(acc->fd); + FREE(acc); + } + } + + /* Wrap up and get out. */ + FREE(this); + return (0); +} + +int evHold(evContext opaqueCtx, evConnID id) { + evConn *this = id.opaque; + + if ((this->flags & EV_CONN_LISTEN) == 0) { + errno = EINVAL; + return (-1); + } + if ((this->flags & EV_CONN_SELECTED) == 0) + return (0); + this->flags &= ~EV_CONN_SELECTED; + return (evDeselectFD(opaqueCtx, this->file)); +} + +int evUnhold(evContext opaqueCtx, evConnID id) { + evConn *this = id.opaque; + int ret; + + if ((this->flags & EV_CONN_LISTEN) == 0) { + errno = EINVAL; + return (-1); + } + if ((this->flags & EV_CONN_SELECTED) != 0) + return (0); + ret = evSelectFD(opaqueCtx, this->fd, EV_READ, listener, this, + &this->file); + if (ret == 0) + this->flags |= EV_CONN_SELECTED; + return (ret); +} + +int +evTryAccept(evContext opaqueCtx, evConnID id, int *sys_errno) { + evContext_p *ctx = opaqueCtx.opaque; + evConn *conn = id.opaque; + evAccept *new; + + if ((conn->flags & EV_CONN_LISTEN) == 0) { + errno = EINVAL; + return (-1); + } + OKNEW(new); + new->conn = conn; + new->ralen = sizeof new->ra; + new->fd = accept(conn->fd, &new->ra.sa, &new->ralen); + if (new->fd > ctx->highestFD) { + close(new->fd); + new->fd = -1; + new->ioErrno = ENOTSOCK; + } + if (new->fd >= 0) { + new->lalen = sizeof new->la; + if (GETXXXNAME(getsockname, new->fd, new->la.sa, new->lalen) < 0) { + new->ioErrno = errno; + (void) close(new->fd); + new->fd = -1; + } else + new->ioErrno = 0; + } else { + new->ioErrno = errno; + if (errno == EAGAIN || errno == EWOULDBLOCK) { + FREE(new); + return (-1); + } + } + INIT_LINK(new, link); + APPEND(ctx->accepts, new, link); + *sys_errno = new->ioErrno; + return (0); +} + +/* Private. */ + +static void +listener(evContext opaqueCtx, void *uap, int fd, int evmask) { + evContext_p *ctx = opaqueCtx.opaque; + evConn *conn = uap; + union { + struct sockaddr sa; + struct sockaddr_in in; +#ifndef NO_SOCKADDR_UN + struct sockaddr_un un; +#endif + } la, ra; + int new; + ISC_SOCKLEN_T lalen = 0, ralen; + + REQUIRE((evmask & EV_READ) != 0); + ralen = sizeof ra; + new = accept(fd, &ra.sa, &ralen); + if (new > ctx->highestFD) { + close(new); + new = -1; + errno = ENOTSOCK; + } + if (new >= 0) { + lalen = sizeof la; + if (GETXXXNAME(getsockname, new, la.sa, lalen) < 0) { + int save = errno; + + (void) close(new); + errno = save; + new = -1; + } + } else if (errno == EAGAIN || errno == EWOULDBLOCK) + return; + (*conn->func)(opaqueCtx, conn->uap, new, &la.sa, lalen, &ra.sa, ralen); +} + +static void +connector(evContext opaqueCtx, void *uap, int fd, int evmask) { + evConn *conn = uap; + union { + struct sockaddr sa; + struct sockaddr_in in; +#ifndef NO_SOCKADDR_UN + struct sockaddr_un un; +#endif + } la, ra; + ISC_SOCKLEN_T lalen, ralen; +#ifndef NETREAD_BROKEN + char buf[1]; +#endif + void *conn_uap; + evConnFunc conn_func; + evConnID id; + int socket_errno = 0; + ISC_SOCKLEN_T optlen; + + UNUSED(evmask); + + lalen = sizeof la; + ralen = sizeof ra; + conn_uap = conn->uap; + conn_func = conn->func; + id.opaque = conn; +#ifdef SO_ERROR + optlen = sizeof socket_errno; + if (fd < 0 && + getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, (char *)&socket_errno, + &optlen) < 0) + socket_errno = errno; + else + errno = socket_errno; +#endif + if (evCancelConn(opaqueCtx, id) < 0 || + socket_errno || +#ifdef NETREAD_BROKEN + 0 || +#else + read(fd, buf, 0) < 0 || +#endif + GETXXXNAME(getsockname, fd, la.sa, lalen) < 0 || + GETXXXNAME(getpeername, fd, ra.sa, ralen) < 0) { + int save = errno; + + (void) close(fd); /*%< XXX closing caller's fd */ + errno = save; + fd = -1; + } + (*conn_func)(opaqueCtx, conn_uap, fd, &la.sa, lalen, &ra.sa, ralen); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/isc/ev_files.c b/contrib/bind-9.5.2/lib/bind/isc/ev_files.c new file mode 100644 index 0000000000..b12baf1aaa --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/ev_files.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1995-1999 by Internet Software Consortium + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +/* ev_files.c - implement asynch file IO for the eventlib + * vix 11sep95 [initial] + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: ev_files.c,v 1.8 2005/07/28 06:51:48 marka Exp $"; +#endif + +#include "port_before.h" +#include "fd_setsize.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include "eventlib_p.h" + +#include "port_after.h" + +static evFile *FindFD(const evContext_p *ctx, int fd, int eventmask); + +int +evSelectFD(evContext opaqueCtx, + int fd, + int eventmask, + evFileFunc func, + void *uap, + evFileID *opaqueID +) { + evContext_p *ctx = opaqueCtx.opaque; + evFile *id; + int mode; + + evPrintf(ctx, 1, + "evSelectFD(ctx %p, fd %d, mask 0x%x, func %p, uap %p)\n", + ctx, fd, eventmask, func, uap); + if (eventmask == 0 || (eventmask & ~EV_MASK_ALL) != 0) + EV_ERR(EINVAL); +#ifndef USE_POLL + if (fd > ctx->highestFD) + EV_ERR(EINVAL); +#endif + OK(mode = fcntl(fd, F_GETFL, NULL)); /*%< side effect: validate fd. */ + /* + * The first time we touch a file descriptor, we need to check to see + * if the application already had it in O_NONBLOCK mode and if so, all + * of our deselect()'s have to leave it in O_NONBLOCK. If not, then + * all but our last deselect() has to leave it in O_NONBLOCK. + */ +#ifdef USE_POLL + /* Make sure both ctx->pollfds[] and ctx->fdTable[] are large enough */ + if (fd >= ctx->maxnfds && evPollfdRealloc(ctx, 1, fd) != 0) + EV_ERR(ENOMEM); +#endif /* USE_POLL */ + id = FindFD(ctx, fd, EV_MASK_ALL); + if (id == NULL) { + if (mode & PORT_NONBLOCK) + FD_SET(fd, &ctx->nonblockBefore); + else { +#ifdef USE_FIONBIO_IOCTL + int on = 1; + OK(ioctl(fd, FIONBIO, (char *)&on)); +#else + OK(fcntl(fd, F_SETFL, mode | PORT_NONBLOCK)); +#endif + FD_CLR(fd, &ctx->nonblockBefore); + } + } + + /* + * If this descriptor is already in use, search for it again to see + * if any of the eventmask bits we want to set are already captured. + * We cannot usefully capture the same fd event more than once in the + * same context. + */ + if (id != NULL && FindFD(ctx, fd, eventmask) != NULL) + EV_ERR(ETOOMANYREFS); + + /* Allocate and fill. */ + OKNEW(id); + id->func = func; + id->uap = uap; + id->fd = fd; + id->eventmask = eventmask; + + /* + * Insert at head. Order could be important for performance if we + * believe that evGetNext()'s accesses to the fd_sets will be more + * serial and therefore more cache-lucky if the list is ordered by + * ``fd.'' We do not believe these things, so we don't do it. + * + * The interesting sequence is where GetNext() has cached a select() + * result and the caller decides to evSelectFD() on some descriptor. + * Since GetNext() starts at the head, it can miss new entries we add + * at the head. This is not a serious problem since the event being + * evSelectFD()'d for has to occur before evSelectFD() is called for + * the file event to be considered "missed" -- a real corner case. + * Maintaining a "tail" pointer for ctx->files would fix this, but I'm + * not sure it would be ``more correct.'' + */ + if (ctx->files != NULL) + ctx->files->prev = id; + id->prev = NULL; + id->next = ctx->files; + ctx->files = id; + + /* Insert into fd table. */ + if (ctx->fdTable[fd] != NULL) + ctx->fdTable[fd]->fdprev = id; + id->fdprev = NULL; + id->fdnext = ctx->fdTable[fd]; + ctx->fdTable[fd] = id; + + /* Turn on the appropriate bits in the {rd,wr,ex}Next fd_set's. */ + if (eventmask & EV_READ) + FD_SET(fd, &ctx->rdNext); + if (eventmask & EV_WRITE) + FD_SET(fd, &ctx->wrNext); + if (eventmask & EV_EXCEPT) + FD_SET(fd, &ctx->exNext); + + /* Update fdMax. */ + if (fd > ctx->fdMax) + ctx->fdMax = fd; + + /* Remember the ID if the caller provided us a place for it. */ + if (opaqueID) + opaqueID->opaque = id; + + return (0); +} + +int +evDeselectFD(evContext opaqueCtx, evFileID opaqueID) { + evContext_p *ctx = opaqueCtx.opaque; + evFile *del = opaqueID.opaque; + evFile *cur; + int mode, eventmask; + + if (!del) { + evPrintf(ctx, 11, "evDeselectFD(NULL) ignored\n"); + errno = EINVAL; + return (-1); + } + + evPrintf(ctx, 1, "evDeselectFD(fd %d, mask 0x%x)\n", + del->fd, del->eventmask); + + /* Get the mode. Unless the file has been closed, errors are bad. */ + mode = fcntl(del->fd, F_GETFL, NULL); + if (mode == -1 && errno != EBADF) + EV_ERR(errno); + + /* Remove from the list of files. */ + if (del->prev != NULL) + del->prev->next = del->next; + else + ctx->files = del->next; + if (del->next != NULL) + del->next->prev = del->prev; + + /* Remove from the fd table. */ + if (del->fdprev != NULL) + del->fdprev->fdnext = del->fdnext; + else + ctx->fdTable[del->fd] = del->fdnext; + if (del->fdnext != NULL) + del->fdnext->fdprev = del->fdprev; + + /* + * If the file descriptor does not appear in any other select() entry, + * and if !EV_WASNONBLOCK, and if we got no EBADF when we got the mode + * earlier, then: restore the fd to blocking status. + */ + if (!(cur = FindFD(ctx, del->fd, EV_MASK_ALL)) && + !FD_ISSET(del->fd, &ctx->nonblockBefore) && + mode != -1) { + /* + * Note that we won't return an error status to the caller if + * this fcntl() fails since (a) we've already done the work + * and (b) the caller didn't ask us anything about O_NONBLOCK. + */ +#ifdef USE_FIONBIO_IOCTL + int off = 0; + (void) ioctl(del->fd, FIONBIO, (char *)&off); +#else + (void) fcntl(del->fd, F_SETFL, mode & ~PORT_NONBLOCK); +#endif + } + + /* + * Now find all other uses of this descriptor and OR together an event + * mask so that we don't turn off {rd,wr,ex}Next bits that some other + * file event is using. As an optimization, stop if the event mask + * fills. + */ + eventmask = 0; + for ((void)NULL; + cur != NULL && eventmask != EV_MASK_ALL; + cur = cur->next) + if (cur->fd == del->fd) + eventmask |= cur->eventmask; + + /* OK, now we know which bits we can clear out. */ + if (!(eventmask & EV_READ)) { + FD_CLR(del->fd, &ctx->rdNext); + if (FD_ISSET(del->fd, &ctx->rdLast)) { + FD_CLR(del->fd, &ctx->rdLast); + ctx->fdCount--; + } + } + if (!(eventmask & EV_WRITE)) { + FD_CLR(del->fd, &ctx->wrNext); + if (FD_ISSET(del->fd, &ctx->wrLast)) { + FD_CLR(del->fd, &ctx->wrLast); + ctx->fdCount--; + } + } + if (!(eventmask & EV_EXCEPT)) { + FD_CLR(del->fd, &ctx->exNext); + if (FD_ISSET(del->fd, &ctx->exLast)) { + FD_CLR(del->fd, &ctx->exLast); + ctx->fdCount--; + } + } + + /* If this was the maxFD, find the new one. */ + if (del->fd == ctx->fdMax) { + ctx->fdMax = -1; + for (cur = ctx->files; cur; cur = cur->next) + if (cur->fd > ctx->fdMax) + ctx->fdMax = cur->fd; + } + + /* If this was the fdNext, cycle that to the next entry. */ + if (del == ctx->fdNext) + ctx->fdNext = del->next; + + /* Couldn't free it before now since we were using fields out of it. */ + FREE(del); + + return (0); +} + +static evFile * +FindFD(const evContext_p *ctx, int fd, int eventmask) { + evFile *id; + + for (id = ctx->fdTable[fd]; id != NULL; id = id->fdnext) + if (id->fd == fd && (id->eventmask & eventmask) != 0) + break; + return (id); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/isc/ev_streams.c b/contrib/bind-9.5.2/lib/bind/isc/ev_streams.c new file mode 100644 index 0000000000..5dad36d04a --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/ev_streams.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +/* ev_streams.c - implement asynch stream file IO for the eventlib + * vix 04mar96 [initial] + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: ev_streams.c,v 1.5 2005/04/27 04:56:36 sra Exp $"; +#endif + +#include "port_before.h" +#include "fd_setsize.h" + +#include +#include + +#include + +#include +#include +#include "eventlib_p.h" + +#include "port_after.h" + +static int copyvec(evStream *str, const struct iovec *iov, int iocnt); +static void consume(evStream *str, size_t bytes); +static void done(evContext opaqueCtx, evStream *str); +static void writable(evContext opaqueCtx, void *uap, int fd, int evmask); +static void readable(evContext opaqueCtx, void *uap, int fd, int evmask); + +struct iovec +evConsIovec(void *buf, size_t cnt) { + struct iovec ret; + + memset(&ret, 0xf5, sizeof ret); + ret.iov_base = buf; + ret.iov_len = cnt; + return (ret); +} + +int +evWrite(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt, + evStreamFunc func, void *uap, evStreamID *id) +{ + evContext_p *ctx = opaqueCtx.opaque; + evStream *new; + int save; + + OKNEW(new); + new->func = func; + new->uap = uap; + new->fd = fd; + new->flags = 0; + if (evSelectFD(opaqueCtx, fd, EV_WRITE, writable, new, &new->file) < 0) + goto free; + if (copyvec(new, iov, iocnt) < 0) + goto free; + new->prevDone = NULL; + new->nextDone = NULL; + if (ctx->streams != NULL) + ctx->streams->prev = new; + new->prev = NULL; + new->next = ctx->streams; + ctx->streams = new; + if (id != NULL) + id->opaque = new; + return (0); + free: + save = errno; + FREE(new); + errno = save; + return (-1); +} + +int +evRead(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt, + evStreamFunc func, void *uap, evStreamID *id) +{ + evContext_p *ctx = opaqueCtx.opaque; + evStream *new; + int save; + + OKNEW(new); + new->func = func; + new->uap = uap; + new->fd = fd; + new->flags = 0; + if (evSelectFD(opaqueCtx, fd, EV_READ, readable, new, &new->file) < 0) + goto free; + if (copyvec(new, iov, iocnt) < 0) + goto free; + new->prevDone = NULL; + new->nextDone = NULL; + if (ctx->streams != NULL) + ctx->streams->prev = new; + new->prev = NULL; + new->next = ctx->streams; + ctx->streams = new; + if (id) + id->opaque = new; + return (0); + free: + save = errno; + FREE(new); + errno = save; + return (-1); +} + +int +evTimeRW(evContext opaqueCtx, evStreamID id, evTimerID timer) /*ARGSUSED*/ { + evStream *str = id.opaque; + + UNUSED(opaqueCtx); + + str->timer = timer; + str->flags |= EV_STR_TIMEROK; + return (0); +} + +int +evUntimeRW(evContext opaqueCtx, evStreamID id) /*ARGSUSED*/ { + evStream *str = id.opaque; + + UNUSED(opaqueCtx); + + str->flags &= ~EV_STR_TIMEROK; + return (0); +} + +int +evCancelRW(evContext opaqueCtx, evStreamID id) { + evContext_p *ctx = opaqueCtx.opaque; + evStream *old = id.opaque; + + /* + * The streams list is doubly threaded. First, there's ctx->streams + * that's used by evDestroy() to find and cancel all streams. Second, + * there's ctx->strDone (head) and ctx->strLast (tail) which thread + * through the potentially smaller number of "IO completed" streams, + * used in evGetNext() to avoid scanning the entire list. + */ + + /* Unlink from ctx->streams. */ + if (old->prev != NULL) + old->prev->next = old->next; + else + ctx->streams = old->next; + if (old->next != NULL) + old->next->prev = old->prev; + + /* + * If 'old' is on the ctx->strDone list, remove it. Update + * ctx->strLast if necessary. + */ + if (old->prevDone == NULL && old->nextDone == NULL) { + /* + * Either 'old' is the only item on the done list, or it's + * not on the done list. If the former, then we unlink it + * from the list. If the latter, we leave the list alone. + */ + if (ctx->strDone == old) { + ctx->strDone = NULL; + ctx->strLast = NULL; + } + } else { + if (old->prevDone != NULL) + old->prevDone->nextDone = old->nextDone; + else + ctx->strDone = old->nextDone; + if (old->nextDone != NULL) + old->nextDone->prevDone = old->prevDone; + else + ctx->strLast = old->prevDone; + } + + /* Deallocate the stream. */ + if (old->file.opaque) + evDeselectFD(opaqueCtx, old->file); + memput(old->iovOrig, sizeof (struct iovec) * old->iovOrigCount); + FREE(old); + return (0); +} + +/* Copy a scatter/gather vector and initialize a stream handler's IO. */ +static int +copyvec(evStream *str, const struct iovec *iov, int iocnt) { + int i; + + str->iovOrig = (struct iovec *)memget(sizeof(struct iovec) * iocnt); + if (str->iovOrig == NULL) { + errno = ENOMEM; + return (-1); + } + str->ioTotal = 0; + for (i = 0; i < iocnt; i++) { + str->iovOrig[i] = iov[i]; + str->ioTotal += iov[i].iov_len; + } + str->iovOrigCount = iocnt; + str->iovCur = str->iovOrig; + str->iovCurCount = str->iovOrigCount; + str->ioDone = 0; + return (0); +} + +/* Pull off or truncate lead iovec(s). */ +static void +consume(evStream *str, size_t bytes) { + while (bytes > 0U) { + if (bytes < (size_t)str->iovCur->iov_len) { + str->iovCur->iov_len -= bytes; + str->iovCur->iov_base = (void *) + ((u_char *)str->iovCur->iov_base + bytes); + str->ioDone += bytes; + bytes = 0; + } else { + bytes -= str->iovCur->iov_len; + str->ioDone += str->iovCur->iov_len; + str->iovCur++; + str->iovCurCount--; + } + } +} + +/* Add a stream to Done list and deselect the FD. */ +static void +done(evContext opaqueCtx, evStream *str) { + evContext_p *ctx = opaqueCtx.opaque; + + if (ctx->strLast != NULL) { + str->prevDone = ctx->strLast; + ctx->strLast->nextDone = str; + ctx->strLast = str; + } else { + INSIST(ctx->strDone == NULL); + ctx->strDone = ctx->strLast = str; + } + evDeselectFD(opaqueCtx, str->file); + str->file.opaque = NULL; + /* evDrop() will call evCancelRW() on us. */ +} + +/* Dribble out some bytes on the stream. (Called by evDispatch().) */ +static void +writable(evContext opaqueCtx, void *uap, int fd, int evmask) { + evStream *str = uap; + int bytes; + + UNUSED(evmask); + + bytes = writev(fd, str->iovCur, str->iovCurCount); + if (bytes > 0) { + if ((str->flags & EV_STR_TIMEROK) != 0) + evTouchIdleTimer(opaqueCtx, str->timer); + consume(str, bytes); + } else { + if (bytes < 0 && errno != EINTR) { + str->ioDone = -1; + str->ioErrno = errno; + } + } + if (str->ioDone == -1 || str->ioDone == str->ioTotal) + done(opaqueCtx, str); +} + +/* Scoop up some bytes from the stream. (Called by evDispatch().) */ +static void +readable(evContext opaqueCtx, void *uap, int fd, int evmask) { + evStream *str = uap; + int bytes; + + UNUSED(evmask); + + bytes = readv(fd, str->iovCur, str->iovCurCount); + if (bytes > 0) { + if ((str->flags & EV_STR_TIMEROK) != 0) + evTouchIdleTimer(opaqueCtx, str->timer); + consume(str, bytes); + } else { + if (bytes == 0) + str->ioDone = 0; + else { + if (errno != EINTR) { + str->ioDone = -1; + str->ioErrno = errno; + } + } + } + if (str->ioDone <= 0 || str->ioDone == str->ioTotal) + done(opaqueCtx, str); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/isc/ev_timers.c b/contrib/bind-9.5.2/lib/bind/isc/ev_timers.c new file mode 100644 index 0000000000..12ac2cebca --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/ev_timers.c @@ -0,0 +1,499 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1995-1999 by Internet Software Consortium + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +/* ev_timers.c - implement timers for the eventlib + * vix 09sep95 [initial] + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: ev_timers.c,v 1.6 2005/04/27 04:56:36 sra Exp $"; +#endif + +/* Import. */ + +#include "port_before.h" +#include "fd_setsize.h" + +#include + +#include +#include +#include "eventlib_p.h" + +#include "port_after.h" + +/* Constants. */ + +#define MILLION 1000000 +#define BILLION 1000000000 + +/* Forward. */ + +static int due_sooner(void *, void *); +static void set_index(void *, int); +static void free_timer(void *, void *); +static void print_timer(void *, void *); +static void idle_timeout(evContext, void *, struct timespec, struct timespec); + +/* Private type. */ + +typedef struct { + evTimerFunc func; + void * uap; + struct timespec lastTouched; + struct timespec max_idle; + evTimer * timer; +} idle_timer; + +/* Public. */ + +struct timespec +evConsTime(time_t sec, long nsec) { + struct timespec x; + + x.tv_sec = sec; + x.tv_nsec = nsec; + return (x); +} + +struct timespec +evAddTime(struct timespec addend1, struct timespec addend2) { + struct timespec x; + + x.tv_sec = addend1.tv_sec + addend2.tv_sec; + x.tv_nsec = addend1.tv_nsec + addend2.tv_nsec; + if (x.tv_nsec >= BILLION) { + x.tv_sec++; + x.tv_nsec -= BILLION; + } + return (x); +} + +struct timespec +evSubTime(struct timespec minuend, struct timespec subtrahend) { + struct timespec x; + + x.tv_sec = minuend.tv_sec - subtrahend.tv_sec; + if (minuend.tv_nsec >= subtrahend.tv_nsec) + x.tv_nsec = minuend.tv_nsec - subtrahend.tv_nsec; + else { + x.tv_nsec = BILLION - subtrahend.tv_nsec + minuend.tv_nsec; + x.tv_sec--; + } + return (x); +} + +int +evCmpTime(struct timespec a, struct timespec b) { + long x = a.tv_sec - b.tv_sec; + + if (x == 0L) + x = a.tv_nsec - b.tv_nsec; + return (x < 0L ? (-1) : x > 0L ? (1) : (0)); +} + +struct timespec +evNowTime() { + struct timeval now; +#ifdef CLOCK_REALTIME + struct timespec tsnow; + int m = CLOCK_REALTIME; + +#ifdef CLOCK_MONOTONIC + if (__evOptMonoTime) + m = CLOCK_MONOTONIC; +#endif + if (clock_gettime(m, &tsnow) == 0) + return (tsnow); +#endif + if (gettimeofday(&now, NULL) < 0) + return (evConsTime(0, 0)); + return (evTimeSpec(now)); +} + +struct timespec +evUTCTime() { + struct timeval now; +#ifdef CLOCK_REALTIME + struct timespec tsnow; + if (clock_gettime(CLOCK_REALTIME, &tsnow) == 0) + return (tsnow); +#endif + if (gettimeofday(&now, NULL) < 0) + return (evConsTime(0, 0)); + return (evTimeSpec(now)); +} + +struct timespec +evLastEventTime(evContext opaqueCtx) { + evContext_p *ctx = opaqueCtx.opaque; + + return (ctx->lastEventTime); +} + +struct timespec +evTimeSpec(struct timeval tv) { + struct timespec ts; + + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = tv.tv_usec * 1000; + return (ts); +} + +struct timeval +evTimeVal(struct timespec ts) { + struct timeval tv; + + tv.tv_sec = ts.tv_sec; + tv.tv_usec = ts.tv_nsec / 1000; + return (tv); +} + +int +evSetTimer(evContext opaqueCtx, + evTimerFunc func, + void *uap, + struct timespec due, + struct timespec inter, + evTimerID *opaqueID +) { + evContext_p *ctx = opaqueCtx.opaque; + evTimer *id; + + evPrintf(ctx, 1, +"evSetTimer(ctx %p, func %p, uap %p, due %ld.%09ld, inter %ld.%09ld)\n", + ctx, func, uap, + (long)due.tv_sec, due.tv_nsec, + (long)inter.tv_sec, inter.tv_nsec); + +#ifdef __hpux + /* + * tv_sec and tv_nsec are unsigned. + */ + if (due.tv_nsec >= BILLION) + EV_ERR(EINVAL); + + if (inter.tv_nsec >= BILLION) + EV_ERR(EINVAL); +#else + if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION) + EV_ERR(EINVAL); + + if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION) + EV_ERR(EINVAL); +#endif + + /* due={0,0} is a magic cookie meaning "now." */ + if (due.tv_sec == (time_t)0 && due.tv_nsec == 0L) + due = evNowTime(); + + /* Allocate and fill. */ + OKNEW(id); + id->func = func; + id->uap = uap; + id->due = due; + id->inter = inter; + + if (heap_insert(ctx->timers, id) < 0) + return (-1); + + /* Remember the ID if the caller provided us a place for it. */ + if (opaqueID) + opaqueID->opaque = id; + + if (ctx->debug > 7) { + evPrintf(ctx, 7, "timers after evSetTimer:\n"); + (void) heap_for_each(ctx->timers, print_timer, (void *)ctx); + } + + return (0); +} + +int +evClearTimer(evContext opaqueCtx, evTimerID id) { + evContext_p *ctx = opaqueCtx.opaque; + evTimer *del = id.opaque; + + if (ctx->cur != NULL && + ctx->cur->type == Timer && + ctx->cur->u.timer.this == del) { + evPrintf(ctx, 8, "deferring delete of timer (executing)\n"); + /* + * Setting the interval to zero ensures that evDrop() will + * clean up the timer. + */ + del->inter = evConsTime(0, 0); + return (0); + } + + if (heap_element(ctx->timers, del->index) != del) + EV_ERR(ENOENT); + + if (heap_delete(ctx->timers, del->index) < 0) + return (-1); + FREE(del); + + if (ctx->debug > 7) { + evPrintf(ctx, 7, "timers after evClearTimer:\n"); + (void) heap_for_each(ctx->timers, print_timer, (void *)ctx); + } + + return (0); +} + +int +evConfigTimer(evContext opaqueCtx, + evTimerID id, + const char *param, + int value +) { + evContext_p *ctx = opaqueCtx.opaque; + evTimer *timer = id.opaque; + int result=0; + + UNUSED(value); + + if (heap_element(ctx->timers, timer->index) != timer) + EV_ERR(ENOENT); + + if (strcmp(param, "rate") == 0) + timer->mode |= EV_TMR_RATE; + else if (strcmp(param, "interval") == 0) + timer->mode &= ~EV_TMR_RATE; + else + EV_ERR(EINVAL); + + return (result); +} + +int +evResetTimer(evContext opaqueCtx, + evTimerID id, + evTimerFunc func, + void *uap, + struct timespec due, + struct timespec inter +) { + evContext_p *ctx = opaqueCtx.opaque; + evTimer *timer = id.opaque; + struct timespec old_due; + int result=0; + + if (heap_element(ctx->timers, timer->index) != timer) + EV_ERR(ENOENT); + +#ifdef __hpux + /* + * tv_sec and tv_nsec are unsigned. + */ + if (due.tv_nsec >= BILLION) + EV_ERR(EINVAL); + + if (inter.tv_nsec >= BILLION) + EV_ERR(EINVAL); +#else + if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION) + EV_ERR(EINVAL); + + if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION) + EV_ERR(EINVAL); +#endif + + old_due = timer->due; + + timer->func = func; + timer->uap = uap; + timer->due = due; + timer->inter = inter; + + switch (evCmpTime(due, old_due)) { + case -1: + result = heap_increased(ctx->timers, timer->index); + break; + case 0: + result = 0; + break; + case 1: + result = heap_decreased(ctx->timers, timer->index); + break; + } + + if (ctx->debug > 7) { + evPrintf(ctx, 7, "timers after evResetTimer:\n"); + (void) heap_for_each(ctx->timers, print_timer, (void *)ctx); + } + + return (result); +} + +int +evSetIdleTimer(evContext opaqueCtx, + evTimerFunc func, + void *uap, + struct timespec max_idle, + evTimerID *opaqueID +) { + evContext_p *ctx = opaqueCtx.opaque; + idle_timer *tt; + + /* Allocate and fill. */ + OKNEW(tt); + tt->func = func; + tt->uap = uap; + tt->lastTouched = ctx->lastEventTime; + tt->max_idle = max_idle; + + if (evSetTimer(opaqueCtx, idle_timeout, tt, + evAddTime(ctx->lastEventTime, max_idle), + max_idle, opaqueID) < 0) { + FREE(tt); + return (-1); + } + + tt->timer = opaqueID->opaque; + + return (0); +} + +int +evClearIdleTimer(evContext opaqueCtx, evTimerID id) { + evTimer *del = id.opaque; + idle_timer *tt = del->uap; + + FREE(tt); + return (evClearTimer(opaqueCtx, id)); +} + +int +evResetIdleTimer(evContext opaqueCtx, + evTimerID opaqueID, + evTimerFunc func, + void *uap, + struct timespec max_idle +) { + evContext_p *ctx = opaqueCtx.opaque; + evTimer *timer = opaqueID.opaque; + idle_timer *tt = timer->uap; + + tt->func = func; + tt->uap = uap; + tt->lastTouched = ctx->lastEventTime; + tt->max_idle = max_idle; + + return (evResetTimer(opaqueCtx, opaqueID, idle_timeout, tt, + evAddTime(ctx->lastEventTime, max_idle), + max_idle)); +} + +int +evTouchIdleTimer(evContext opaqueCtx, evTimerID id) { + evContext_p *ctx = opaqueCtx.opaque; + evTimer *t = id.opaque; + idle_timer *tt = t->uap; + + tt->lastTouched = ctx->lastEventTime; + + return (0); +} + +/* Public to the rest of eventlib. */ + +heap_context +evCreateTimers(const evContext_p *ctx) { + + UNUSED(ctx); + + return (heap_new(due_sooner, set_index, 2048)); +} + +void +evDestroyTimers(const evContext_p *ctx) { + (void) heap_for_each(ctx->timers, free_timer, NULL); + (void) heap_free(ctx->timers); +} + +/* Private. */ + +static int +due_sooner(void *a, void *b) { + evTimer *a_timer, *b_timer; + + a_timer = a; + b_timer = b; + return (evCmpTime(a_timer->due, b_timer->due) < 0); +} + +static void +set_index(void *what, int index) { + evTimer *timer; + + timer = what; + timer->index = index; +} + +static void +free_timer(void *what, void *uap) { + evTimer *t = what; + + UNUSED(uap); + + FREE(t); +} + +static void +print_timer(void *what, void *uap) { + evTimer *cur = what; + evContext_p *ctx = uap; + + cur = what; + evPrintf(ctx, 7, + " func %p, uap %p, due %ld.%09ld, inter %ld.%09ld\n", + cur->func, cur->uap, + (long)cur->due.tv_sec, cur->due.tv_nsec, + (long)cur->inter.tv_sec, cur->inter.tv_nsec); +} + +static void +idle_timeout(evContext opaqueCtx, + void *uap, + struct timespec due, + struct timespec inter +) { + evContext_p *ctx = opaqueCtx.opaque; + idle_timer *this = uap; + struct timespec idle; + + UNUSED(due); + UNUSED(inter); + + idle = evSubTime(ctx->lastEventTime, this->lastTouched); + if (evCmpTime(idle, this->max_idle) >= 0) { + (this->func)(opaqueCtx, this->uap, this->timer->due, + this->max_idle); + /* + * Setting the interval to zero will cause the timer to + * be cleaned up in evDrop(). + */ + this->timer->inter = evConsTime(0, 0); + FREE(this); + } else { + /* evDrop() will reschedule the timer. */ + this->timer->inter = evSubTime(this->max_idle, idle); + } +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/isc/ev_waits.c b/contrib/bind-9.5.2/lib/bind/isc/ev_waits.c new file mode 100644 index 0000000000..99da1526c7 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/ev_waits.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +/* ev_waits.c - implement deferred function calls for the eventlib + * vix 05dec95 [initial] + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: ev_waits.c,v 1.4 2005/04/27 04:56:36 sra Exp $"; +#endif + +#include "port_before.h" +#include "fd_setsize.h" + +#include + +#include +#include +#include "eventlib_p.h" + +#include "port_after.h" + +/* Forward. */ + +static void print_waits(evContext_p *ctx); +static evWaitList * evNewWaitList(evContext_p *); +static void evFreeWaitList(evContext_p *, evWaitList *); +static evWaitList * evGetWaitList(evContext_p *, const void *, int); + + +/* Public. */ + +/*% + * Enter a new wait function on the queue. + */ +int +evWaitFor(evContext opaqueCtx, const void *tag, + evWaitFunc func, void *uap, evWaitID *id) +{ + evContext_p *ctx = opaqueCtx.opaque; + evWait *new; + evWaitList *wl = evGetWaitList(ctx, tag, 1); + + OKNEW(new); + new->func = func; + new->uap = uap; + new->tag = tag; + new->next = NULL; + if (wl->last != NULL) + wl->last->next = new; + else + wl->first = new; + wl->last = new; + if (id != NULL) + id->opaque = new; + if (ctx->debug >= 9) + print_waits(ctx); + return (0); +} + +/*% + * Mark runnable all waiting functions having a certain tag. + */ +int +evDo(evContext opaqueCtx, const void *tag) { + evContext_p *ctx = opaqueCtx.opaque; + evWaitList *wl = evGetWaitList(ctx, tag, 0); + evWait *first; + + if (!wl) { + errno = ENOENT; + return (-1); + } + + first = wl->first; + INSIST(first != NULL); + + if (ctx->waitDone.last != NULL) + ctx->waitDone.last->next = first; + else + ctx->waitDone.first = first; + ctx->waitDone.last = wl->last; + evFreeWaitList(ctx, wl); + + return (0); +} + +/*% + * Remove a waiting (or ready to run) function from the queue. + */ +int +evUnwait(evContext opaqueCtx, evWaitID id) { + evContext_p *ctx = opaqueCtx.opaque; + evWait *this, *prev; + evWaitList *wl; + int found = 0; + + this = id.opaque; + INSIST(this != NULL); + wl = evGetWaitList(ctx, this->tag, 0); + if (wl != NULL) { + for (prev = NULL, this = wl->first; + this != NULL; + prev = this, this = this->next) + if (this == (evWait *)id.opaque) { + found = 1; + if (prev != NULL) + prev->next = this->next; + else + wl->first = this->next; + if (wl->last == this) + wl->last = prev; + if (wl->first == NULL) + evFreeWaitList(ctx, wl); + break; + } + } + + if (!found) { + /* Maybe it's done */ + for (prev = NULL, this = ctx->waitDone.first; + this != NULL; + prev = this, this = this->next) + if (this == (evWait *)id.opaque) { + found = 1; + if (prev != NULL) + prev->next = this->next; + else + ctx->waitDone.first = this->next; + if (ctx->waitDone.last == this) + ctx->waitDone.last = prev; + break; + } + } + + if (!found) { + errno = ENOENT; + return (-1); + } + + FREE(this); + + if (ctx->debug >= 9) + print_waits(ctx); + + return (0); +} + +int +evDefer(evContext opaqueCtx, evWaitFunc func, void *uap) { + evContext_p *ctx = opaqueCtx.opaque; + evWait *new; + + OKNEW(new); + new->func = func; + new->uap = uap; + new->tag = NULL; + new->next = NULL; + if (ctx->waitDone.last != NULL) + ctx->waitDone.last->next = new; + else + ctx->waitDone.first = new; + ctx->waitDone.last = new; + if (ctx->debug >= 9) + print_waits(ctx); + return (0); +} + +/* Private. */ + +static void +print_waits(evContext_p *ctx) { + evWaitList *wl; + evWait *this; + + evPrintf(ctx, 9, "wait waiting:\n"); + for (wl = ctx->waitLists; wl != NULL; wl = wl->next) { + INSIST(wl->first != NULL); + evPrintf(ctx, 9, " tag %p:", wl->first->tag); + for (this = wl->first; this != NULL; this = this->next) + evPrintf(ctx, 9, " %p", this); + evPrintf(ctx, 9, "\n"); + } + evPrintf(ctx, 9, "wait done:"); + for (this = ctx->waitDone.first; this != NULL; this = this->next) + evPrintf(ctx, 9, " %p", this); + evPrintf(ctx, 9, "\n"); +} + +static evWaitList * +evNewWaitList(evContext_p *ctx) { + evWaitList *new; + + NEW(new); + if (new == NULL) + return (NULL); + new->first = new->last = NULL; + new->prev = NULL; + new->next = ctx->waitLists; + if (new->next != NULL) + new->next->prev = new; + ctx->waitLists = new; + return (new); +} + +static void +evFreeWaitList(evContext_p *ctx, evWaitList *this) { + + INSIST(this != NULL); + + if (this->prev != NULL) + this->prev->next = this->next; + else + ctx->waitLists = this->next; + if (this->next != NULL) + this->next->prev = this->prev; + FREE(this); +} + +static evWaitList * +evGetWaitList(evContext_p *ctx, const void *tag, int should_create) { + evWaitList *this; + + for (this = ctx->waitLists; this != NULL; this = this->next) { + if (this->first != NULL && this->first->tag == tag) + break; + } + if (this == NULL && should_create) + this = evNewWaitList(ctx); + return (this); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/isc/eventlib.c b/contrib/bind-9.5.2/lib/bind/isc/eventlib.c new file mode 100644 index 0000000000..be4a7848b9 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/eventlib.c @@ -0,0 +1,933 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1995-1999 by Internet Software Consortium + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +/* eventlib.c - implement glue for the eventlib + * vix 09sep95 [initial] + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: eventlib.c,v 1.10 2006/03/09 23:57:56 marka Exp $"; +#endif + +#include "port_before.h" +#include "fd_setsize.h" + +#include +#include +#include +#ifdef SOLARIS2 +#include +#endif /* SOLARIS2 */ + +#include +#include +#include +#include +#include + +#include +#include +#include "eventlib_p.h" + +#include "port_after.h" + +int __evOptMonoTime; + +#ifdef USE_POLL +#define pselect Pselect +#endif /* USE_POLL */ + +/* Forward. */ + +#if defined(NEED_PSELECT) || defined(USE_POLL) +static int pselect(int, void *, void *, void *, + struct timespec *, + const sigset_t *); +#endif + +int __evOptMonoTime; + +/* Public. */ + +int +evCreate(evContext *opaqueCtx) { + evContext_p *ctx; + + /* Make sure the memory heap is initialized. */ + if (meminit(0, 0) < 0 && errno != EEXIST) + return (-1); + + OKNEW(ctx); + + /* Global. */ + ctx->cur = NULL; + + /* Debugging. */ + ctx->debug = 0; + ctx->output = NULL; + + /* Connections. */ + ctx->conns = NULL; + INIT_LIST(ctx->accepts); + + /* Files. */ + ctx->files = NULL; +#ifdef USE_POLL + ctx->pollfds = NULL; + ctx->maxnfds = 0; + ctx->firstfd = 0; + emulMaskInit(ctx, rdLast, EV_READ, 1); + emulMaskInit(ctx, rdNext, EV_READ, 0); + emulMaskInit(ctx, wrLast, EV_WRITE, 1); + emulMaskInit(ctx, wrNext, EV_WRITE, 0); + emulMaskInit(ctx, exLast, EV_EXCEPT, 1); + emulMaskInit(ctx, exNext, EV_EXCEPT, 0); + emulMaskInit(ctx, nonblockBefore, EV_WASNONBLOCKING, 0); +#endif /* USE_POLL */ + FD_ZERO(&ctx->rdNext); + FD_ZERO(&ctx->wrNext); + FD_ZERO(&ctx->exNext); + FD_ZERO(&ctx->nonblockBefore); + ctx->fdMax = -1; + ctx->fdNext = NULL; + ctx->fdCount = 0; /*%< Invalidate {rd,wr,ex}Last. */ +#ifndef USE_POLL + ctx->highestFD = FD_SETSIZE - 1; + memset(ctx->fdTable, 0, sizeof ctx->fdTable); +#else + ctx->highestFD = INT_MAX / sizeof(struct pollfd); + ctx->fdTable = NULL; +#endif /* USE_POLL */ +#ifdef EVENTLIB_TIME_CHECKS + ctx->lastFdCount = 0; +#endif + + /* Streams. */ + ctx->streams = NULL; + ctx->strDone = NULL; + ctx->strLast = NULL; + + /* Timers. */ + ctx->lastEventTime = evNowTime(); +#ifdef EVENTLIB_TIME_CHECKS + ctx->lastSelectTime = ctx->lastEventTime; +#endif + ctx->timers = evCreateTimers(ctx); + if (ctx->timers == NULL) + return (-1); + + /* Waits. */ + ctx->waitLists = NULL; + ctx->waitDone.first = ctx->waitDone.last = NULL; + ctx->waitDone.prev = ctx->waitDone.next = NULL; + + opaqueCtx->opaque = ctx; + return (0); +} + +void +evSetDebug(evContext opaqueCtx, int level, FILE *output) { + evContext_p *ctx = opaqueCtx.opaque; + + ctx->debug = level; + ctx->output = output; +} + +int +evDestroy(evContext opaqueCtx) { + evContext_p *ctx = opaqueCtx.opaque; + int revs = 424242; /*%< Doug Adams. */ + evWaitList *this_wl, *next_wl; + evWait *this_wait, *next_wait; + + /* Connections. */ + while (revs-- > 0 && ctx->conns != NULL) { + evConnID id; + + id.opaque = ctx->conns; + (void) evCancelConn(opaqueCtx, id); + } + INSIST(revs >= 0); + + /* Streams. */ + while (revs-- > 0 && ctx->streams != NULL) { + evStreamID id; + + id.opaque = ctx->streams; + (void) evCancelRW(opaqueCtx, id); + } + + /* Files. */ + while (revs-- > 0 && ctx->files != NULL) { + evFileID id; + + id.opaque = ctx->files; + (void) evDeselectFD(opaqueCtx, id); + } + INSIST(revs >= 0); + + /* Timers. */ + evDestroyTimers(ctx); + + /* Waits. */ + for (this_wl = ctx->waitLists; + revs-- > 0 && this_wl != NULL; + this_wl = next_wl) { + next_wl = this_wl->next; + for (this_wait = this_wl->first; + revs-- > 0 && this_wait != NULL; + this_wait = next_wait) { + next_wait = this_wait->next; + FREE(this_wait); + } + FREE(this_wl); + } + for (this_wait = ctx->waitDone.first; + revs-- > 0 && this_wait != NULL; + this_wait = next_wait) { + next_wait = this_wait->next; + FREE(this_wait); + } + + FREE(ctx); + return (0); +} + +int +evGetNext(evContext opaqueCtx, evEvent *opaqueEv, int options) { + evContext_p *ctx = opaqueCtx.opaque; + struct timespec nextTime; + evTimer *nextTimer; + evEvent_p *new; + int x, pselect_errno, timerPast; +#ifdef EVENTLIB_TIME_CHECKS + struct timespec interval; +#endif + + /* Ensure that exactly one of EV_POLL or EV_WAIT was specified. */ + x = ((options & EV_POLL) != 0) + ((options & EV_WAIT) != 0); + if (x != 1) + EV_ERR(EINVAL); + + /* Get the time of day. We'll do this again after select() blocks. */ + ctx->lastEventTime = evNowTime(); + + again: + /* Finished accept()'s do not require a select(). */ + if (!EMPTY(ctx->accepts)) { + OKNEW(new); + new->type = Accept; + new->u.accept.this = HEAD(ctx->accepts); + UNLINK(ctx->accepts, HEAD(ctx->accepts), link); + opaqueEv->opaque = new; + return (0); + } + + /* Stream IO does not require a select(). */ + if (ctx->strDone != NULL) { + OKNEW(new); + new->type = Stream; + new->u.stream.this = ctx->strDone; + ctx->strDone = ctx->strDone->nextDone; + if (ctx->strDone == NULL) + ctx->strLast = NULL; + opaqueEv->opaque = new; + return (0); + } + + /* Waits do not require a select(). */ + if (ctx->waitDone.first != NULL) { + OKNEW(new); + new->type = Wait; + new->u.wait.this = ctx->waitDone.first; + ctx->waitDone.first = ctx->waitDone.first->next; + if (ctx->waitDone.first == NULL) + ctx->waitDone.last = NULL; + opaqueEv->opaque = new; + return (0); + } + + /* Get the status and content of the next timer. */ + if ((nextTimer = heap_element(ctx->timers, 1)) != NULL) { + nextTime = nextTimer->due; + timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0); + } else + timerPast = 0; /*%< Make gcc happy. */ + evPrintf(ctx, 9, "evGetNext: fdCount %d\n", ctx->fdCount); + if (ctx->fdCount == 0) { + static const struct timespec NoTime = {0, 0L}; + enum { JustPoll, Block, Timer } m; + struct timespec t, *tp; + + /* Are there any events at all? */ + if ((options & EV_WAIT) != 0 && !nextTimer && ctx->fdMax == -1) + EV_ERR(ENOENT); + + /* Figure out what select()'s timeout parameter should be. */ + if ((options & EV_POLL) != 0) { + m = JustPoll; + t = NoTime; + tp = &t; + } else if (nextTimer == NULL) { + m = Block; + /* ``t'' unused. */ + tp = NULL; + } else if (timerPast) { + m = JustPoll; + t = NoTime; + tp = &t; + } else { + m = Timer; + /* ``t'' filled in later. */ + tp = &t; + } +#ifdef EVENTLIB_TIME_CHECKS + if (ctx->debug > 0) { + interval = evSubTime(ctx->lastEventTime, + ctx->lastSelectTime); + if (interval.tv_sec > 0 || interval.tv_nsec > 0) + evPrintf(ctx, 1, + "time between pselect() %u.%09u count %d\n", + interval.tv_sec, interval.tv_nsec, + ctx->lastFdCount); + } +#endif + do { +#ifndef USE_POLL + /* XXX need to copy only the bits we are using. */ + ctx->rdLast = ctx->rdNext; + ctx->wrLast = ctx->wrNext; + ctx->exLast = ctx->exNext; +#else + /* + * The pollfd structure uses separate fields for + * the input and output events (corresponding to + * the ??Next and ??Last fd sets), so there's no + * need to copy one to the other. + */ +#endif /* USE_POLL */ + if (m == Timer) { + INSIST(tp == &t); + t = evSubTime(nextTime, ctx->lastEventTime); + } + + /* XXX should predict system's earliness and adjust. */ + x = pselect(ctx->fdMax+1, + &ctx->rdLast, &ctx->wrLast, &ctx->exLast, + tp, NULL); + pselect_errno = errno; + +#ifndef USE_POLL + evPrintf(ctx, 4, "select() returns %d (err: %s)\n", + x, (x == -1) ? strerror(errno) : "none"); +#else + evPrintf(ctx, 4, "poll() returns %d (err: %s)\n", + x, (x == -1) ? strerror(errno) : "none"); +#endif /* USE_POLL */ + /* Anything but a poll can change the time. */ + if (m != JustPoll) + ctx->lastEventTime = evNowTime(); + + /* Select() likes to finish about 10ms early. */ + } while (x == 0 && m == Timer && + evCmpTime(ctx->lastEventTime, nextTime) < 0); +#ifdef EVENTLIB_TIME_CHECKS + ctx->lastSelectTime = ctx->lastEventTime; +#endif + if (x < 0) { + if (pselect_errno == EINTR) { + if ((options & EV_NULL) != 0) + goto again; + OKNEW(new); + new->type = Null; + /* No data. */ + opaqueEv->opaque = new; + return (0); + } + if (pselect_errno == EBADF) { + for (x = 0; x <= ctx->fdMax; x++) { + struct stat sb; + + if (FD_ISSET(x, &ctx->rdNext) == 0 && + FD_ISSET(x, &ctx->wrNext) == 0 && + FD_ISSET(x, &ctx->exNext) == 0) + continue; + if (fstat(x, &sb) == -1 && + errno == EBADF) + evPrintf(ctx, 1, "EBADF: %d\n", + x); + } + abort(); + } + EV_ERR(pselect_errno); + } + if (x == 0 && (nextTimer == NULL || !timerPast) && + (options & EV_POLL)) + EV_ERR(EWOULDBLOCK); + ctx->fdCount = x; +#ifdef EVENTLIB_TIME_CHECKS + ctx->lastFdCount = x; +#endif + } + INSIST(nextTimer || ctx->fdCount); + + /* Timers go first since we'd like them to be accurate. */ + if (nextTimer && !timerPast) { + /* Has anything happened since we blocked? */ + timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0); + } + if (nextTimer && timerPast) { + OKNEW(new); + new->type = Timer; + new->u.timer.this = nextTimer; + opaqueEv->opaque = new; + return (0); + } + + /* No timers, so there should be a ready file descriptor. */ + x = 0; + while (ctx->fdCount > 0) { + evFile *fid; + int fd, eventmask; + + if (ctx->fdNext == NULL) { + if (++x == 2) { + /* + * Hitting the end twice means that the last + * select() found some FD's which have since + * been deselected. + * + * On some systems, the count returned by + * selects is the total number of bits in + * all masks that are set, and on others it's + * the number of fd's that have some bit set, + * and on others, it's just broken. We + * always assume that it's the number of + * bits set in all masks, because that's what + * the man page says it should do, and + * the worst that can happen is we do an + * extra select(). + */ + ctx->fdCount = 0; + break; + } + ctx->fdNext = ctx->files; + } + fid = ctx->fdNext; + ctx->fdNext = fid->next; + + fd = fid->fd; + eventmask = 0; + if (FD_ISSET(fd, &ctx->rdLast)) + eventmask |= EV_READ; + if (FD_ISSET(fd, &ctx->wrLast)) + eventmask |= EV_WRITE; + if (FD_ISSET(fd, &ctx->exLast)) + eventmask |= EV_EXCEPT; + eventmask &= fid->eventmask; + if (eventmask != 0) { + if ((eventmask & EV_READ) != 0) { + FD_CLR(fd, &ctx->rdLast); + ctx->fdCount--; + } + if ((eventmask & EV_WRITE) != 0) { + FD_CLR(fd, &ctx->wrLast); + ctx->fdCount--; + } + if ((eventmask & EV_EXCEPT) != 0) { + FD_CLR(fd, &ctx->exLast); + ctx->fdCount--; + } + OKNEW(new); + new->type = File; + new->u.file.this = fid; + new->u.file.eventmask = eventmask; + opaqueEv->opaque = new; + return (0); + } + } + if (ctx->fdCount < 0) { + /* + * select()'s count is off on a number of systems, and + * can result in fdCount < 0. + */ + evPrintf(ctx, 4, "fdCount < 0 (%d)\n", ctx->fdCount); + ctx->fdCount = 0; + } + + /* We get here if the caller deselect()'s an FD. Gag me with a goto. */ + goto again; +} + +int +evDispatch(evContext opaqueCtx, evEvent opaqueEv) { + evContext_p *ctx = opaqueCtx.opaque; + evEvent_p *ev = opaqueEv.opaque; +#ifdef EVENTLIB_TIME_CHECKS + void *func; + struct timespec start_time; + struct timespec interval; +#endif + +#ifdef EVENTLIB_TIME_CHECKS + if (ctx->debug > 0) + start_time = evNowTime(); +#endif + ctx->cur = ev; + switch (ev->type) { + case Accept: { + evAccept *this = ev->u.accept.this; + + evPrintf(ctx, 5, + "Dispatch.Accept: fd %d -> %d, func %p, uap %p\n", + this->conn->fd, this->fd, + this->conn->func, this->conn->uap); + errno = this->ioErrno; + (this->conn->func)(opaqueCtx, this->conn->uap, this->fd, + &this->la, this->lalen, + &this->ra, this->ralen); +#ifdef EVENTLIB_TIME_CHECKS + func = this->conn->func; +#endif + break; + } + case File: { + evFile *this = ev->u.file.this; + int eventmask = ev->u.file.eventmask; + + evPrintf(ctx, 5, + "Dispatch.File: fd %d, mask 0x%x, func %p, uap %p\n", + this->fd, this->eventmask, this->func, this->uap); + (this->func)(opaqueCtx, this->uap, this->fd, eventmask); +#ifdef EVENTLIB_TIME_CHECKS + func = this->func; +#endif + break; + } + case Stream: { + evStream *this = ev->u.stream.this; + + evPrintf(ctx, 5, + "Dispatch.Stream: fd %d, func %p, uap %p\n", + this->fd, this->func, this->uap); + errno = this->ioErrno; + (this->func)(opaqueCtx, this->uap, this->fd, this->ioDone); +#ifdef EVENTLIB_TIME_CHECKS + func = this->func; +#endif + break; + } + case Timer: { + evTimer *this = ev->u.timer.this; + + evPrintf(ctx, 5, "Dispatch.Timer: func %p, uap %p\n", + this->func, this->uap); + (this->func)(opaqueCtx, this->uap, this->due, this->inter); +#ifdef EVENTLIB_TIME_CHECKS + func = this->func; +#endif + break; + } + case Wait: { + evWait *this = ev->u.wait.this; + + evPrintf(ctx, 5, + "Dispatch.Wait: tag %p, func %p, uap %p\n", + this->tag, this->func, this->uap); + (this->func)(opaqueCtx, this->uap, this->tag); +#ifdef EVENTLIB_TIME_CHECKS + func = this->func; +#endif + break; + } + case Null: { + /* No work. */ +#ifdef EVENTLIB_TIME_CHECKS + func = NULL; +#endif + break; + } + default: { + abort(); + } + } +#ifdef EVENTLIB_TIME_CHECKS + if (ctx->debug > 0) { + interval = evSubTime(evNowTime(), start_time); + /* + * Complain if it took longer than 50 milliseconds. + * + * We call getuid() to make an easy to find mark in a kernel + * trace. + */ + if (interval.tv_sec > 0 || interval.tv_nsec > 50000000) + evPrintf(ctx, 1, + "dispatch interval %u.%09u uid %d type %d func %p\n", + interval.tv_sec, interval.tv_nsec, + getuid(), ev->type, func); + } +#endif + ctx->cur = NULL; + evDrop(opaqueCtx, opaqueEv); + return (0); +} + +void +evDrop(evContext opaqueCtx, evEvent opaqueEv) { + evContext_p *ctx = opaqueCtx.opaque; + evEvent_p *ev = opaqueEv.opaque; + + switch (ev->type) { + case Accept: { + FREE(ev->u.accept.this); + break; + } + case File: { + /* No work. */ + break; + } + case Stream: { + evStreamID id; + + id.opaque = ev->u.stream.this; + (void) evCancelRW(opaqueCtx, id); + break; + } + case Timer: { + evTimer *this = ev->u.timer.this; + evTimerID opaque; + + /* Check to see whether the user func cleared the timer. */ + if (heap_element(ctx->timers, this->index) != this) { + evPrintf(ctx, 5, "Dispatch.Timer: timer rm'd?\n"); + break; + } + /* + * Timer is still there. Delete it if it has expired, + * otherwise set it according to its next interval. + */ + if (this->inter.tv_sec == (time_t)0 && + this->inter.tv_nsec == 0L) { + opaque.opaque = this; + (void) evClearTimer(opaqueCtx, opaque); + } else { + opaque.opaque = this; + (void) evResetTimer(opaqueCtx, opaque, this->func, + this->uap, + evAddTime((this->mode & EV_TMR_RATE) ? + this->due : + ctx->lastEventTime, + this->inter), + this->inter); + } + break; + } + case Wait: { + FREE(ev->u.wait.this); + break; + } + case Null: { + /* No work. */ + break; + } + default: { + abort(); + } + } + FREE(ev); +} + +int +evMainLoop(evContext opaqueCtx) { + evEvent event; + int x; + + while ((x = evGetNext(opaqueCtx, &event, EV_WAIT)) == 0) + if ((x = evDispatch(opaqueCtx, event)) < 0) + break; + return (x); +} + +int +evHighestFD(evContext opaqueCtx) { + evContext_p *ctx = opaqueCtx.opaque; + + return (ctx->highestFD); +} + +void +evPrintf(const evContext_p *ctx, int level, const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + if (ctx->output != NULL && ctx->debug >= level) { + vfprintf(ctx->output, fmt, ap); + fflush(ctx->output); + } + va_end(ap); +} + +int +evSetOption(evContext *opaqueCtx, const char *option, int value) { + /* evContext_p *ctx = opaqueCtx->opaque; */ + + UNUSED(opaqueCtx); + UNUSED(value); +#ifndef CLOCK_MONOTONIC + UNUSED(option); +#endif + +#ifdef CLOCK_MONOTONIC + if (strcmp(option, "monotime") == 0) { + if (opaqueCtx != NULL) + errno = EINVAL; + if (value == 0 || value == 1) { + __evOptMonoTime = value; + return (0); + } else { + errno = EINVAL; + return (-1); + } + } +#endif + errno = ENOENT; + return (-1); +} + +int +evGetOption(evContext *opaqueCtx, const char *option, int *value) { + /* evContext_p *ctx = opaqueCtx->opaque; */ + + UNUSED(opaqueCtx); +#ifndef CLOCK_MONOTONIC + UNUSED(value); + UNUSED(option); +#endif + +#ifdef CLOCK_MONOTONIC + if (strcmp(option, "monotime") == 0) { + if (opaqueCtx != NULL) + errno = EINVAL; + *value = __evOptMonoTime; + return (0); + } +#endif + errno = ENOENT; + return (-1); +} + +#if defined(NEED_PSELECT) || defined(USE_POLL) +/* XXX needs to move to the porting library. */ +static int +pselect(int nfds, void *rfds, void *wfds, void *efds, + struct timespec *tsp, + const sigset_t *sigmask) +{ + struct timeval tv, *tvp; + sigset_t sigs; + int n; +#ifdef USE_POLL + int polltimeout = INFTIM; + evContext_p *ctx; + struct pollfd *fds; + nfds_t pnfds; + + UNUSED(nfds); +#endif /* USE_POLL */ + + if (tsp) { + tvp = &tv; + tv = evTimeVal(*tsp); +#ifdef USE_POLL + polltimeout = 1000 * tv.tv_sec + tv.tv_usec / 1000; +#endif /* USE_POLL */ + } else + tvp = NULL; + if (sigmask) + sigprocmask(SIG_SETMASK, sigmask, &sigs); +#ifndef USE_POLL + n = select(nfds, rfds, wfds, efds, tvp); +#else + /* + * rfds, wfds, and efds should all be from the same evContext_p, + * so any of them will do. If they're all NULL, the caller is + * presumably calling us to block. + */ + if (rfds != NULL) + ctx = ((__evEmulMask *)rfds)->ctx; + else if (wfds != NULL) + ctx = ((__evEmulMask *)wfds)->ctx; + else if (efds != NULL) + ctx = ((__evEmulMask *)efds)->ctx; + else + ctx = NULL; + if (ctx != NULL && ctx->fdMax != -1) { + fds = &(ctx->pollfds[ctx->firstfd]); + pnfds = ctx->fdMax - ctx->firstfd + 1; + } else { + fds = NULL; + pnfds = 0; + } + n = poll(fds, pnfds, polltimeout); + if (n > 0) { + int i, e; + + INSIST(ctx != NULL); + for (e = 0, i = ctx->firstfd; i <= ctx->fdMax; i++) { + if (ctx->pollfds[i].fd < 0) + continue; + if (FD_ISSET(i, &ctx->rdLast)) + e++; + if (FD_ISSET(i, &ctx->wrLast)) + e++; + if (FD_ISSET(i, &ctx->exLast)) + e++; + } + n = e; + } +#endif /* USE_POLL */ + if (sigmask) + sigprocmask(SIG_SETMASK, &sigs, NULL); + if (tsp) + *tsp = evTimeSpec(tv); + return (n); +} +#endif + +#ifdef USE_POLL +int +evPollfdRealloc(evContext_p *ctx, int pollfd_chunk_size, int fd) { + + int i, maxnfds; + void *pollfds, *fdTable; + + if (fd < ctx->maxnfds) + return (0); + + /* Don't allow ridiculously small values for pollfd_chunk_size */ + if (pollfd_chunk_size < 20) + pollfd_chunk_size = 20; + + maxnfds = (1 + (fd/pollfd_chunk_size)) * pollfd_chunk_size; + + pollfds = realloc(ctx->pollfds, maxnfds * sizeof(*ctx->pollfds)); + if (pollfds != NULL) + ctx->pollfds = pollfds; + fdTable = realloc(ctx->fdTable, maxnfds * sizeof(*ctx->fdTable)); + if (fdTable != NULL) + ctx->fdTable = fdTable; + + if (pollfds == NULL || fdTable == NULL) { + evPrintf(ctx, 2, "pollfd() realloc (%ld) failed\n", + (long)maxnfds*sizeof(struct pollfd)); + return (-1); + } + + for (i = ctx->maxnfds; i < maxnfds; i++) { + ctx->pollfds[i].fd = -1; + ctx->pollfds[i].events = 0; + ctx->fdTable[i] = 0; + } + + ctx->maxnfds = maxnfds; + + return (0); +} + +/* Find the appropriate 'events' or 'revents' field in the pollfds array */ +short * +__fd_eventfield(int fd, __evEmulMask *maskp) { + + evContext_p *ctx = (evContext_p *)maskp->ctx; + + if (!maskp->result || maskp->type == EV_WASNONBLOCKING) + return (&(ctx->pollfds[fd].events)); + else + return (&(ctx->pollfds[fd].revents)); +} + +/* Translate to poll(2) event */ +short +__poll_event(__evEmulMask *maskp) { + + switch ((maskp)->type) { + case EV_READ: + return (POLLRDNORM); + case EV_WRITE: + return (POLLWRNORM); + case EV_EXCEPT: + return (POLLRDBAND | POLLPRI | POLLWRBAND); + case EV_WASNONBLOCKING: + return (POLLHUP); + default: + return (0); + } +} + +/* + * Clear the events corresponding to the specified mask. If this leaves + * the events mask empty (apart from the POLLHUP bit), set the fd field + * to -1 so that poll(2) will ignore this fd. + */ +void +__fd_clr(int fd, __evEmulMask *maskp) { + + evContext_p *ctx = maskp->ctx; + + *__fd_eventfield(fd, maskp) &= ~__poll_event(maskp); + if ((ctx->pollfds[fd].events & ~POLLHUP) == 0) { + ctx->pollfds[fd].fd = -1; + if (fd == ctx->fdMax) + while (ctx->fdMax > ctx->firstfd && + ctx->pollfds[ctx->fdMax].fd < 0) + ctx->fdMax--; + if (fd == ctx->firstfd) + while (ctx->firstfd <= ctx->fdMax && + ctx->pollfds[ctx->firstfd].fd < 0) + ctx->firstfd++; + /* + * Do we have a empty set of descriptors? + */ + if (ctx->firstfd > ctx->fdMax) { + ctx->fdMax = -1; + ctx->firstfd = 0; + } + } +} + +/* + * Set the events bit(s) corresponding to the specified mask. If the events + * field has any other bits than POLLHUP set, also set the fd field so that + * poll(2) will watch this fd. + */ +void +__fd_set(int fd, __evEmulMask *maskp) { + + evContext_p *ctx = maskp->ctx; + + *__fd_eventfield(fd, maskp) |= __poll_event(maskp); + if ((ctx->pollfds[fd].events & ~POLLHUP) != 0) { + ctx->pollfds[fd].fd = fd; + if (fd < ctx->firstfd || ctx->fdMax == -1) + ctx->firstfd = fd; + if (fd > ctx->fdMax) + ctx->fdMax = fd; + } +} +#endif /* USE_POLL */ + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/isc/eventlib.mdoc b/contrib/bind-9.5.2/lib/bind/isc/eventlib.mdoc new file mode 100644 index 0000000000..5e9cd85b1b --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/eventlib.mdoc @@ -0,0 +1,918 @@ +.\" $Id: eventlib.mdoc,v 1.3 2004/03/09 06:30:08 marka Exp $ +.\" +.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (c) 1995-1999 by Internet Software Consortium +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND 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. +.\" +.Dd March 6, 1996 +.Dt EVENTLIB 3 +.Os BSD 4 +.Sh NAME +.Nm evConnFunc , +.Nm evFileFunc , +.Nm evStreamFunc , +.Nm evTimerFunc , +.Nm evWaitFunc , +.Nm evCreate , +.Nm evDestroy , +.Nm evGetNext , +.Nm evDispatch , +.Nm evDrop , +.Nm evMainLoop , +.Nm evConsTime , +.Nm evTimeSpec , +.Nm evTimeVal , +.Nm evAddTime , +.Nm evSubTime , +.Nm evCmpTime , +.Nm evNowTime , +.Nm evUTCTime , +.Nm evLastEventTime , +.Nm evSetTimer , +.Nm evResetTimer , +.Nm evConfigTimer , +.Nm evClearTimer , +.Nm evSetIdleTimer , +.Nm evTouchIdleTimer , +.Nm evClearIdleTimer , +.Nm evWaitFor , +.Nm evDo , +.Nm evUnwait , +.Nm evDefer , +.Nm evSelectFD , +.Nm evDeselectFD , +.Nm evWrite , +.Nm evRead , +.Nm evCancelRW , +.Nm evTimeRW , +.Nm evUntimeRW , +.Nm evListen , +.Nm evConnect , +.Nm evCancelConn , +.Nm evHold , +.Nm evUnhold , +.Nm evTryAccept , +.Nm evConsIovec , +.Nm evSetDebug , +.Nm evPrintf , +.Nm evInitID , +.Nm evTestID , +.Nm evGetOption , +.Nm evSetOption +.Nd event handling library +.Sh SYNOPSIS +.Fd #include +.Ft typedef void +.Fn \*(lp*evConnFunc\*(rp "evContext ctx" "void *uap" "int fd" \ +"const void *la" "int lalen" "const void *ra" "int ralen" +.Ft typedef void +.Fn \*(lp*evTimerFunc\*(rp "evContext ctx" "void *uap" \ +"struct timespec due" "struct timespec inter" +.Ft typedef void +.Fn \*(lp*evFileFunc\*(rp "evContext ctx" "void *uap" "int fd" "int eventmask" +.Ft typedef void +.Fn \*(lp*evStreamFunc\*(rp "evContext ctx" "void *uap" "int fd" "int bytes" +.Ft typedef void +.Fn \*(lp*evWaitFunc\*(rp "evContext ctx" "void *uap" "const void *tag" +.Ft int +.Fn evCreate "evContext *ctx" +.Ft int +.Fn evDestroy "evContext ctx" +.Ft int +.Fn evGetNext "evContext ctx" "evEvent *ev" "int options" +.Ft int +.Fn evDispatch "evContext ctx" "evEvent ev" +.Ft void +.Fn evDrop "evContext ctx" "evEvent ev" +.Ft int +.Fn evMainLoop "evContext ctx" +.Ft struct timespec +.Fn evConsTime "int sec" "int usec" +.Ft struct timespec +.Fn evTimeSpec "struct timeval tv" +.Ft struct timeval +.Fn evTimeVal "struct timespec ts" +.Ft struct timespec +.Fn evAddTime "struct timespec addend1" "struct timespec addend2" +.Ft struct timespec +.Fn evSubTime "struct timespec minuend" "struct timespec subtrahend" +.Ft struct timespec +.Fn evCmpTime "struct timespec a" "struct timespec b" +.Ft struct timespec +.Fn evNowTime "void" +.Ft struct timespec +.Fn evUTCTime "void" +.Ft struct timespec +.Fn evLastEventTime "evContext opaqueCtx" +.Ft int +.Fn evSetTimer "evContext ctx" "evTimerFunc func" "void *uap" \ +"struct timespec due" "struct timespec inter" "evTimerID *id" +.Ft int +.Fn evResetTimer "evContext ctx" "evTimerID id" "evTimerFunc func" \ +"void *uap" "struct timespec due" "struct timespec inter" +.Ft int +.Fn evConfigTimer "evContext ctx" "evTimerID id" "const char *param" \ +"int value" +.Ft int +.Fn evClearTimer "evContext ctx" "evTimerID id" +.Ft int +.Fn evSetIdleTimer "evContext opaqueCtx" "evTimerFunc func" "void *uap" \ +"struct timespec max_idle" "evTimerID *opaqueID" +.Ft int +.Fn evTouchIdleTimer "evContext opaqueCtx" "evTimerID id" +.Ft int +.Fn evResetIdleTimer "evContext opaqueCtx" "evTimerID id" "evTimerFunc func" \ +"void *uap" "struct timespec max_idle" +.Ft int +.Fn evClearIdleTimer "evContext opaqueCtx" "evTimerID id" +.Ft int +.Fn evWaitFor "evContext opaqueCtx" "const void *tag" \ +"evWaitFunc func" "void *uap" "evWaitID *id" +.Ft int +.Fn evDo "evContext opaqueCtx" "const void *tag" +.Ft int +.Fn evUnwait "evContext opaqueCtx" "evWaitID id" +.Ft int +.Fn evDefer "evContext opaqueCtx" "evWaitFunc func" "void *uap" +.Ft int +.Fn evSelectFD "evContext ctx" "int fd" "int eventmask" \ +"evFileFunc func" "void *uap" "evFileID *id" +.Ft int +.Fn evDeselectFD "evContext ctx" "evFileID id" +.Ft struct iovec +.Fn evConsIovec "void *buf" "size_t cnt" +.Ft int +.Fn evWrite "evContext ctx" "int fd" "const struct iovec *iov" "int cnt" \ +"evStreamFunc func" "void *uap" "evStreamID *id" +.Ft int +.Fn evRead "evContext ctx" "int fd" "const struct iovec *iov" "int cnt" \ +"evStreamFunc func" "void *uap" "evStreamID *id" +.Ft int +.Fn evCancelRW "evContext ctx" "evStreamID id" +.Ft int +.Fn evTimeRW "evContext opaqueCtx" "evStreamID id" "evTimerID timer" +.Ft int +.Fn evUntimeRW "evContext opaqueCtx" "evStreamID id" +.Ft int +.Fn evListen "evContext ctx" "int fd" "int maxconn" \ +"evConnFunc func" "void *uap" "evConnID *id" +.Ft int +.Fn evConnect "evContext ctx" "int fd" "void *ra" "int ralen" \ +"evConnFunc func" "void *uap" "evConnID *id" +.Ft int +.Fn evCancelConn "evContext ctx" "evConnID id" +.Ft int +.Fn evHold "evContext ctx" "evConnID id" +.Ft int +.Fn evUnhold "evContext ctx" "evConnID id" +.Ft int +.Fn evTryAccept "evContext ctx" "evConnID id" "int *sys_errno" +.Ft void +.Fn evSetDebug "evContext ctx" "int level" "FILE *output" +.Ft void +.Fn evPrintf "const evContext_p *ctx" "int level" "const char *fmt" "..." +.Ft void +.Fn evInitID "*\s-1ID\s+1" +.Ft int +.Fn evTestID "\s-1ID\s+1" +.Ft int +.Fn evGetOption "evContext *ctx" "const char *option" "int *ret" +.Ft int +.Fn evSetOption "evContext *ctx" "const char *option" "int val" +.Sh DESCRIPTION +This library provides multiple outstanding asynchronous timers and I/O +to a cooperating application. The model is similar to that of the X +Toolkit, in that events are registered with the library and the application +spends most of its time in the +.Fn evMainLoop +function. If an application already has a main loop, it can safely register +events with this library as long as it periodically calls the +.Fn evGetNext +and +.Fn evDispatch +functions. (Note that +.Fn evGetNext +has both polling and blocking modes.) +.Pp +The function +.Fn evCreate +creates an event context which is needed by all the other functions in this +library. All information used internally by this library is bound to this +context, rather than to static storage. This makes the library +.Dq thread safe , +and permits other library functions to use events without +disrupting the application's use of events. +.Pp +The function +.Fn evDestroy +destroys a context that has been created by +.Fn evCreate . +All dynamic memory bound to this context will be freed. An implicit +.Fn evTimerClear +will be done on all timers set in this event context. An implicit +.Fn evDeselectFD +will be done on all file descriptors selected in this event context. +.Pp +The function +.Fn evGetNext +potentially waits for and then retrieves the next asynchronous event, +placing it in the object of the +.Fa ev +pointer argument. The following +.Fa options +are available: +.Fa EV_POLL , +meaning that +.Fn evGetNext +should not block, but rather return +.Dq Fa -1 +with +.Fa errno +set to +.Fa EWOULDBLOCK +if no events have occurred; +.Fa EV_WAIT , +which tells +.Fn evGetNext +to block internally until the next event occurs; and +.Fa EV_NULL , +which tells +.Fn evGetNext +that it should return a special +.Dq no-op +event, which is ignored by +.Fn evDispatch +but handled correctly by +.Fn evDrop . +.Fa EV_NULL +can be necessary to the correct functioning of a caller\-written equivilent to +.Fn evMainLoop , +wherein perterbations caused by external system events must be polled for, and +the default behaviour of internally ignoring such events is undesirable. +Note that +.Fa EV_POLL +and +.Fa EV_WAIT +are mutually exclusive. +.Pp +The function +.Fn evDispatch +dispatches an event retrieved by +.Fn evGetNext . +This usually involves calling the function that was associated with the event +when the event was registered with +.Fn evSetTimer , +.Fn evResetTimer , +or +.Fn evSelectFD . +All events retrieved by +.Fn evGetNext +must be given over to +.Fn evDispatch +at some point, since there is some dynamic memory associated with each event. +.Pp +The function +.Fn evDrop +deallocates dynamic memory that has been allocated by +.Fn evGetNext . +Calling +.Fn evDispatch +has the side effect of calling +.Fn evDrop , +but if you are going to drop the event rather than dispatch it, you will have +to call +.Fn evDrop +directly. +.Pp +The function +.Fn evMainLoop +is just: +.Bd -literal -offset indent +while ((x = evGetNext(opaqueCtx, &event, EV_WAIT)) == 0) + if ((x = evDispatch(opaqueCtx, event)) < 0) + break; +return (x); +.Ed +.Pp +In other words, get events and dispatch them until an error occurs. One such +error would be that all the events under this context become unregistered; in +that event, there will be nothing to wait for and +.Fn evGetNext +becomes an undefined operation. +.Pp +The function +.Fn evConsTime +is a constructor for +.Dq Fa struct timespec +which allows these structures to be created and then passed as arguments to +other functions without the use of temporary variables. (If C had inline +constructors, there would be no need for this function.) +.Pp +The functions +.Fn evTimeSpec +and +.Fn evTimeVal +are utilities which allow the caller to convert a +.Dq Fa struct timeval +to a +.Dq Fa struct timespec +(the function of +.Fn evTimeSpec ) +or vice versa (the function of +.Fn evTimeVal ) . +Note that the name of the function indicates the type of the return value. +.Pp +The function +.Fn evAddTime +adds two +.Dq Fa struct timespec +values and returns the result as a +.Dq Fa struct timespec . +.Pp +The function +.Fn evSubTime +subtracts its second +.Dq Fa struct timespec +argument from its first +.Dq Fa struct timespec +argument and returns the result as a +.Dq Fa struct timespec . +.Pp +The function +.Fn evCmpTime +compares its two +.Dq Fa struct timespec +arguments and returns an +.Dq Fa int +that is less than zero if the first argument specifies an earlier time than +the second, or more than zero if the first argument specifies a later time +than the second, or equal to zero if both arguments specify the same time. +.Pp +The function +.Fn evNowTime +returns a +.Dq Fa struct timespec +which either describes the current time +(using +.Xr clock_gettime 2 or +.Xr gettimeofday 2 ) , +if successful, or has its fields set to zero, if there is an error. +(In the latter case, the caller can check +.Va errno , +since it will be set by +.Xr gettimeofday 2 . ) +The timestamp returned may not be UTC time if +the "monotime" option has been enabled with +.Fn evSetOption . +.Pp +The function +.Fn evUTCTime +is like +.Fn evNowTime +except the result is always on the UTC timescale. +.Pp +The function +.Fn evLastEventTime +returns the +.Dq Fa struct timespec +which describes the last time that certain events happened to the +event context indicated by +.Fa opaqueCtx . +This value is updated by +.Fn evCreate +and +.Fn evGetNext +(upon entry and after +.Xr select 2 +returns); it is routinely compared with other times in the internal handling +of, e.g., timers. +.Pp +The function +.Fn evSetTimer +registers a timer event, which will be delivered as a function call to the +function specified by the +.Fa func +argument. The event will be delivered at absolute time +.Fa due , +and then if time +.Fa inter +is not equal to +.Dq Fn evConsTime 0 0 , +subsequently at intervals equal to time +.Fa inter . +As a special case, specifying a +.Fa due +argument equal to +.Dq Fn evConsTime 0 0 +means +.Dq due immediately . +The +.Fa opaqueID +argument, if specified as a value other than +.Fa NULL , +will be used to store the resulting +.Dq timer \s-1ID\s+1 , +useful as an argument to +.Fn evClearTimer . +Note that in a +.Dq one\-shot +timer (which has an +.Fa inter +argument equal to +.Dq Fa evConsTime(0,0) ) +the user function +.Fa func +should deallocate any dynamic memory that is uniquely bound to the +.Fa uap , +since no handles to this memory will exist within the event library +after a one\-shot timer has been delivered. +.Pp +The function +.Fn evResetTimer +resets the values of the timer specified by +.Fa id +to the given arguments. The arguments are the same as in the description of +.Fn evSetTimer +above. +.Pp +The function +.Fn evClearTimer +will unregister the timer event specified by +.Fa id . +Note that if the +.Fa uap +specified in the corresponding +.Fn evSetTimer +call is uniquely bound to any dynamic memory, then that dynamic memory should +be freed by the caller before the handle is lost. After a call to +.Fn evClearTimer , +no handles to this +.Fa uap +will exist within the event library. +.Pp +The function +.Fn evConfigTimer +can be used to manipulate other aspects of a timer. +Currently two modes are defined "rate" and "interval" which affect the +way recurrent timers are scheduled. +The default mode is "interval" where the event gets scheduled +.Fa inter +after last time it was run. +If mode "rate" is selected the event gets scheduled +.Fa inter +after last time it was scheduled. +For both "rate" and "interval" the numerical argument +.Fa value +is ignored. +.Pp +The function +.Fn evSetIdleTimer +is similar to (and built on) +.Fn evSetTimer ; +it registers an idle timer event which provides for the function call to +.Fa func +to occur. However, for an +.Em idle +timer, the call will occur after at least +.Dq Fa max_idle +time has passed since the time the idle timer was +.Dq last touched ; +originally, this is set to the time returned by +.Fn evLastEventTime +(described above) for the event context specified by +.Fa opaqueCtx . +This is a +.Dq one\-shot +timer, but the time at which the +.Fa func +is actually called can be changed by recourse to +.Fn evTouchIdleTimer +(described below). The pointer to the underlying +.Dq timer \s-1ID\s+1 +is returned in +.Fa opaqueID , +if it is +.No non- Ns Dv NULL . +.Pp +The +.Fn evTouchIdleTimer +function updates the idle timer associated with +.Fa id , +setting its idea of the time it was last accessed to the value returned by +.Fn evLastEventTime +(described above) for the event context specified by +.Fa opaqueCtx . +This means that the idle timer will expire after at least +.Fa max_idle +time has passed since this (possibly new) time, providing a caller mechanism +for resetting the call to the +.Fa func +associated with the idle timer. (See the description of +.Fn evSetIdleTimer , +above, for information about +.Fa func +and +.Fa max_idle . ) +.Pp +The +.Fn evResetIdleTimer +function reschedules a timer and resets the callback function and its argument. +Note that resetting a timer also ``touches'' it. +.Pp +The +.Fn evClearIdleTimer +function unregisters the idle timer associated with +.Fa id . +See the discussion under +.Fn evClearTimer , +above, for information regarding caller handling of the +.Fa uap +associated with the corresponding +.Fn evSetIdleTimer +call. +.Pp +The function +.Fn evWaitFor +places the function +.Fa func +on the given event context's wait queue with the associated (possibly +.Dv NULL ) +.Dq Fa tag ; +if +.Fa id +is +.No non- Ns Dv NULL , +then it will contain the +.Dq wait \s-1ID\s+1 +associated with the created queue element. +.Pp +The function +.Fn evDo +marks +.Em all +of the +.Dq waiting +functions in the given event context's wait queue with the associated (possibly +.Dv NULL ) +.Dq Fa tag +as runnable. This places these functions in a +.Dq done +queue which will be read by +.Fn evGetNext . +.Pp +The function +.Fn evUnwait +will search for the +.Dq wait \s-1ID\s+1 +.Fa id +in the wait queue of the given event context; if an element with the given +.Fa id +is not found, then the +.Dq done +queue of that context is searched. If found, the queue element is removed +from the appropriate list. +.Pp +The function +.Fn evDefer +causes a function (specified as +.Fa func , +with argument +.Fa uap ) +to be dispatched at some later time. Note that the +.Fa tag +argument to +.Fa func +will always be +.Fa NULL +when dispatched. +.Pp +The function +.Fn evSelectFD +registers a file I/O event for the file descriptor specified by +.Fa fd . +Bits in the +.Fa eventmask +argument are named +.Fa EV_READ , +.Fa EV_WRITE , +and +.Fa EV_EXCEPT . +At least one of these bits must be specified. If the +.Fa id +argument is not equal to +.Fa NULL , +it will be used to store a unique ``file event \s-1ID\s+1'' for this event, +which is useful in subsequent calls to +.Fn evDeselectFD . +A file descriptor will be made nonblocking using the +.Fa O_NONBLOCK +flag with +.Xr fcntl 2 +on its first concurrent registration via +.Fn evSelectFD . +An +.Fn evSelectFD +remains in effect until cancelled via +.Fn evDeselectFD . +.Pp +The function +.Fn evDeselectFD +unregisters the ``file event'' specified by the +.Fa id +argument. If the corresponding +.Fa uap +uniquely points to dynamic memory, that memory should be freed before its +handle is lost, since after a call to +.Fn evDeselectFD , +no handles to this event's +.Fa uap +will remain within the event library. A file descriptor will be taken out of +nonblocking mode (see +.Fa O_NONBLOCK +and +.Xr fcntl 2 ) +when its last event registration is removed via +.Fn evDeselectFD , +if it was in blocking mode before the first registration via +.Fn evSelectFD . +.Pp +The function +.Fn evConsIovec +is a constructor for a single +.Ft struct iovec +structure, which is useful for +.Fn evWrite +and +.Fn evRead . +.Pp +The functions +.Fn evWrite +and +.Fn evRead +start asynchronous stream I/O operations on file descriptor +.Fa fd . +The data to be written or read is in the scatter/gather descriptor specified by +.Fa iov +and +.Fa cnt . +The supplied function +.Fa func +will be called with argument +.Fa uap +when the I/O operation is complete. If +.Fa id +is not +.Fa NULL , +it will be filled a with the stream event identifier suitable for use with +.Fn evCancelRW . +.Pp +The function +.Fn evCancelRW +extinguishes an outstanding +.Fn evWrite +or +.Fn evRead +call. System I/O calls cannot always be cancelled, but you are guaranteed +that the +.Fa func +function supplied to +.Fn evWrite +or +.Fn evRead +will not be called after a call to +.Fn evCancelRW . +Care should be taken not to deallocate or otherwise reuse the space pointed +to by the segment descriptors in +.Fa iov +unless the underlying file descriptor is closed first. +.Pp +The function +.Fn evTimeRW +sets the stream associated with the given stream \s-1ID\s+1 +.Dq Fa id +to have the idle timer associated with the timer \s-1ID\s+1 +.Dq Fa timer . +.Pp +The function +.Fn evUntimeRW +says that the stream associated with the given stream \s-1ID\s+1 +.Dq Fa id +should ignore its idle timer, if present. +.Pp +The functions +.Fn evListen , +.Fn evConnect , +and +.Fn evCancelConn +can be used to manage asynchronous incoming and outgoing socket connections. +Sockets to be used with these functions should first be created with +.Xr socket 2 +and given a local name with +.Xr bind 2 . +It is extremely unlikely that the same socket will ever be +useful for both incoming and outgoing connections. The +.Fa id +argument to +.Fn evListen +and +.Fn evConnect +is either +.Fa NULL +or the address of a +.Ft evFileID +variable which can then be used in a subsequent call to +.Fn evCancelConn . +.Pp +After a call to +.Fn evListen , +each incoming connection arriving on +.Fa fd +will cause +.Fa func +to be called with +.Fa uap +as one of its arguments. +.Fn evConnect +initiates an outgoing connection on +.Fa fd +to destination address +.Fa ra +(whose length is +.Fa ralen ) . +When the connection is complete, +.Fa func +will be called with +.Fa uap +as one of its arguments. The argument +.Fa fd +to +.Fn \*(lp*func\*(rp +will be +.Fa -1 +if an error occurred that prevented this connection from completing +successfully. In this case +.Fn errno +will have been set and the socket described by +.Fa fd +will have been closed. The +.Fn evCancelConn +function will prevent delivery of all pending and subsequent +events for the outstanding connection. The +.Fn evHold +function will suspend the acceptance of new connections on the listener +specified by +.Fa id . +Connections will be queued by the protocol stack up to the system's limit. The +.Fn evUnhold +function will reverse the effects of +.Fn evHold , +allowing incoming connections to be delivered for listener +.Fa id . +The +.Fn evTryAccept +function will poll the listener specified by +.Fa id , +accepting a new connection if one is available, and queuing a connection event +for later retrieval by +.Fn evGetNext . +If the connection event queued is an accept error(), sys_errno will contain +the error code; otherwise it will be zero. All connection events queued by +.Fn evTryAccept +will be delivered by +.Fn evGetNext +before a new select is done on the listener. +.Pp +The function +.Fn evSetDebug +sets the debugging +.Fa level +and diagnostic +.Fa output +file handle for an event context. Greater numeric levels will +result in more verbose output being sent to the output FILE during program +execution. +.Pp +The function +.Fn evPrintf +prints a message with the format +.Dq Fa fmt +and the following arguments (if any), on the output stream associated +with the event context pointed to by +.Fa ctx . +The message is output if the event context's debug level is greater than +or equal to the indicated +.Fa level . +.Pp +The function +.Fn evInitID +will initialize an opaque +.Dq evConn \s-1ID\s+1 , +.Dq evFile \s-1ID\s+1 , +.Dq evStream \s-1ID\s+1 , +.Dq evTimer \s-1ID\s+1 , +.Dq evWait \s-1ID\s+1 , +.Dq evContext , +or +.Dq evEvent , +which is passed by reference to a state which +.Fn evTestID +will recognize. +This is useful to make a handle as "not in use". +.Pp +The function +.Fn evTestID +will examine an opaque \s-1ID\s+1 and return +.Dq TRUE +only if it is not in its initialized state. +.Pp +The functions +.Fn evGetOption +and +.Fn evSetOption +can be used to inspect and modify options. +Currently there is only one option, "monotime" and it is global for all +instances of eventlib so the ctx argument must be passed as NULL. +.Pp +The default value for the "monotime" option is zero which selects +the UTC timescale. +When set to a value of one, eventlib will use the +CLOCK_MONOTONIC timescale from +.Xr clock_gettime +instead. +The CLOCK_MONOTONIC timescale is never stepped and should +run at a rate as close to TAI as possible, so it is unaffected +when the system clock is set. +If timerevents should run at a predictable rate, set the value +to one, of they should run at a predictable time of day, leave +it at zero. +If the CLOCK_MONOTONIC timescale is not available on the system, +attempts to set/get this option will fail. +.Sh RETURN VALUES +All the functions whose return type is +.Dq Fa int +use the standard convention of returning zero (0) to indicate success, or +returning +.Dq Fa -1 +and setting +.Fa errno +to indicate failure. +.Sh FILE +.Pa heap.h , +which is in the +.Pa src/lib/isc +directory of the current +.Sy BIND +distribution. +.Sh ERRORS +The possible values for +.Fa errno +when one of the +.Dq Fa int +functions in this library returns +.Dq Fa -1 +include those of the Standard C Library and also: +.Bl -tag -width EWOULDBLOCKAA +.It Bq Er EINVAL +Some function argument has an unreasonable value. +.It Bq Er EINVAL +The specified file descriptor has an integer value greater than the default +.Fa FD_SETSIZE , +meaning that the application's limit is higher than the library's. +.It Bq Er ENOENT +The specified +.Dq event \s-1ID\s+1 +does not exist. +.It Bq Er EWOULDBLOCK +No events have occurred and the +.Fa EV_POLL +option was specified. +.It Bq Er EBADF +The specified signal was unblocked outside the library. +.El +.Sh SEE ALSO +.Xr gettimeofday 2 , +.Xr select 2 , +.Xr fcntl 3 , +.Xr malloc 3 , +.Xr @INDOT@named @SYS_OPS_EXT@ , +.Xr readv 3 , +.Xr writev 3 . +.Sh BUGS +This huge man page needs to be broken up into a handful of smaller ones. +.Sh HISTORY +The +.Nm eventlib +library was designed by Paul Vixie with excellent advice from his friends +and with tips 'o the cap to the X Consortium and the implementors of DEC SRC +Modula-3. diff --git a/contrib/bind-9.5.2/lib/bind/isc/eventlib_p.h b/contrib/bind-9.5.2/lib/bind/isc/eventlib_p.h new file mode 100644 index 0000000000..0a3614ab23 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/eventlib_p.h @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2005 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1995-1999 by Internet Software Consortium + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +/*! \file + * \brief private interfaces for eventlib + * \author vix 09sep95 [initial] + * + * $Id: eventlib_p.h,v 1.9 2006/03/09 23:57:56 marka Exp $ + */ + +#ifndef _EVENTLIB_P_H +#define _EVENTLIB_P_H + +#include +#include +#include +#include +#include + +#define EVENTLIB_DEBUG 1 + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define EV_MASK_ALL (EV_READ | EV_WRITE | EV_EXCEPT) +#define EV_ERR(e) return (errno = (e), -1) +#define OK(x) if ((x) < 0) EV_ERR(errno); else (void)NULL +#define OKFREE(x, y) if ((x) < 0) { FREE((y)); EV_ERR(errno); } \ + else (void)NULL + +#define NEW(p) if (((p) = memget(sizeof *(p))) != NULL) \ + FILL(p); \ + else \ + (void)NULL; +#define OKNEW(p) if (!((p) = memget(sizeof *(p)))) { \ + errno = ENOMEM; \ + return (-1); \ + } else \ + FILL(p) +#define FREE(p) memput((p), sizeof *(p)) + +#if EVENTLIB_DEBUG +#define FILL(p) memset((p), 0xF5, sizeof *(p)) +#else +#define FILL(p) +#endif + +#ifdef USE_POLL +#ifdef HAVE_STROPTS_H +#include +#endif +#include +#endif /* USE_POLL */ + +typedef struct evConn { + evConnFunc func; + void * uap; + int fd; + int flags; +#define EV_CONN_LISTEN 0x0001 /*%< Connection is a listener. */ +#define EV_CONN_SELECTED 0x0002 /*%< evSelectFD(conn->file). */ +#define EV_CONN_BLOCK 0x0004 /*%< Listener fd was blocking. */ + evFileID file; + struct evConn * prev; + struct evConn * next; +} evConn; + +typedef struct evAccept { + int fd; + union { + struct sockaddr sa; + struct sockaddr_in in; +#ifndef NO_SOCKADDR_UN + struct sockaddr_un un; +#endif + } la; + ISC_SOCKLEN_T lalen; + union { + struct sockaddr sa; + struct sockaddr_in in; +#ifndef NO_SOCKADDR_UN + struct sockaddr_un un; +#endif + } ra; + ISC_SOCKLEN_T ralen; + int ioErrno; + evConn * conn; + LINK(struct evAccept) link; +} evAccept; + +typedef struct evFile { + evFileFunc func; + void * uap; + int fd; + int eventmask; + int preemptive; + struct evFile * prev; + struct evFile * next; + struct evFile * fdprev; + struct evFile * fdnext; +} evFile; + +typedef struct evStream { + evStreamFunc func; + void * uap; + evFileID file; + evTimerID timer; + int flags; +#define EV_STR_TIMEROK 0x0001 /*%< IFF timer valid. */ + int fd; + struct iovec * iovOrig; + int iovOrigCount; + struct iovec * iovCur; + int iovCurCount; + int ioTotal; + int ioDone; + int ioErrno; + struct evStream *prevDone, *nextDone; + struct evStream *prev, *next; +} evStream; + +typedef struct evTimer { + evTimerFunc func; + void * uap; + struct timespec due, inter; + int index; + int mode; +#define EV_TMR_RATE 1 +} evTimer; + +typedef struct evWait { + evWaitFunc func; + void * uap; + const void * tag; + struct evWait * next; +} evWait; + +typedef struct evWaitList { + evWait * first; + evWait * last; + struct evWaitList * prev; + struct evWaitList * next; +} evWaitList; + +typedef struct evEvent_p { + enum { Accept, File, Stream, Timer, Wait, Free, Null } type; + union { + struct { evAccept *this; } accept; + struct { evFile *this; int eventmask; } file; + struct { evStream *this; } stream; + struct { evTimer *this; } timer; + struct { evWait *this; } wait; + struct { struct evEvent_p *next; } free; + struct { const void *placeholder; } null; + } u; +} evEvent_p; + +#ifdef USE_POLL +typedef struct { + void *ctx; /* pointer to the evContext_p */ + uint32_t type; /* READ, WRITE, EXCEPT, nonblk */ + uint32_t result; /* 1 => revents, 0 => events */ +} __evEmulMask; + +#define emulMaskInit(ctx, field, ev, lastnext) \ + ctx->field.ctx = ctx; \ + ctx->field.type = ev; \ + ctx->field.result = lastnext; + +extern short *__fd_eventfield(int fd, __evEmulMask *maskp); +extern short __poll_event(__evEmulMask *maskp); +extern void __fd_clr(int fd, __evEmulMask *maskp); +extern void __fd_set(int fd, __evEmulMask *maskp); + +#undef FD_ZERO +#define FD_ZERO(maskp) + +#undef FD_SET +#define FD_SET(fd, maskp) \ + __fd_set(fd, maskp) + +#undef FD_CLR +#define FD_CLR(fd, maskp) \ + __fd_clr(fd, maskp) + +#undef FD_ISSET +#define FD_ISSET(fd, maskp) \ + ((*__fd_eventfield(fd, maskp) & __poll_event(maskp)) != 0) + +#endif /* USE_POLL */ + +typedef struct { + /* Global. */ + const evEvent_p *cur; + /* Debugging. */ + int debug; + FILE *output; + /* Connections. */ + evConn *conns; + LIST(evAccept) accepts; + /* Files. */ + evFile *files, *fdNext; +#ifndef USE_POLL + fd_set rdLast, rdNext; + fd_set wrLast, wrNext; + fd_set exLast, exNext; + fd_set nonblockBefore; + int fdMax, fdCount, highestFD; + evFile *fdTable[FD_SETSIZE]; +#else + struct pollfd *pollfds; /* Allocated as needed */ + evFile **fdTable; /* Ditto */ + int maxnfds; /* # elements in above */ + int firstfd; /* First active fd */ + int fdMax; /* Last active fd */ + int fdCount; /* # fd:s with I/O */ + int highestFD; /* max fd allowed by OS */ + __evEmulMask rdLast, rdNext; + __evEmulMask wrLast, wrNext; + __evEmulMask exLast, exNext; + __evEmulMask nonblockBefore; +#endif /* USE_POLL */ +#ifdef EVENTLIB_TIME_CHECKS + struct timespec lastSelectTime; + int lastFdCount; +#endif + /* Streams. */ + evStream *streams; + evStream *strDone, *strLast; + /* Timers. */ + struct timespec lastEventTime; + heap_context timers; + /* Waits. */ + evWaitList *waitLists; + evWaitList waitDone; +} evContext_p; + +/* eventlib.c */ +#define evPrintf __evPrintf +void evPrintf(const evContext_p *ctx, int level, const char *fmt, ...) + ISC_FORMAT_PRINTF(3, 4); + +#ifdef USE_POLL +extern int evPollfdRealloc(evContext_p *ctx, int pollfd_chunk_size, int fd); +#endif /* USE_POLL */ + +/* ev_timers.c */ +#define evCreateTimers __evCreateTimers +heap_context evCreateTimers(const evContext_p *); +#define evDestroyTimers __evDestroyTimers +void evDestroyTimers(const evContext_p *); + +/* ev_waits.c */ +#define evFreeWait __evFreeWait +evWait *evFreeWait(evContext_p *ctx, evWait *old); + +/* Global options */ +extern int __evOptMonoTime; + +#endif /*_EVENTLIB_P_H*/ diff --git a/contrib/bind-9.5.2/lib/bind/isc/heap.c b/contrib/bind-9.5.2/lib/bind/isc/heap.c new file mode 100644 index 0000000000..3d22b6fc71 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/heap.c @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1997,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +/*% + * Heap implementation of priority queues adapted from the following: + * + * _Introduction to Algorithms_, Cormen, Leiserson, and Rivest, + * MIT Press / McGraw Hill, 1990, ISBN 0-262-03141-8, chapter 7. + * + * _Algorithms_, Second Edition, Sedgewick, Addison-Wesley, 1988, + * ISBN 0-201-06673-4, chapter 11. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: heap.c,v 1.4 2006/03/09 23:57:56 marka Exp $"; +#endif /* not lint */ + +#include "port_before.h" + +#include +#include +#include + +#include "port_after.h" + +#include + +/*% + * Note: to make heap_parent and heap_left easy to compute, the first + * element of the heap array is not used; i.e. heap subscripts are 1-based, + * not 0-based. + */ +#define heap_parent(i) ((i) >> 1) +#define heap_left(i) ((i) << 1) + +#define ARRAY_SIZE_INCREMENT 512 + +heap_context +heap_new(heap_higher_priority_func higher_priority, heap_index_func index, + int array_size_increment) { + heap_context ctx; + + if (higher_priority == NULL) + return (NULL); + + ctx = (heap_context)malloc(sizeof (struct heap_context)); + if (ctx == NULL) + return (NULL); + + ctx->array_size = 0; + if (array_size_increment == 0) + ctx->array_size_increment = ARRAY_SIZE_INCREMENT; + else + ctx->array_size_increment = array_size_increment; + ctx->heap_size = 0; + ctx->heap = NULL; + ctx->higher_priority = higher_priority; + ctx->index = index; + return (ctx); +} + +int +heap_free(heap_context ctx) { + if (ctx == NULL) { + errno = EINVAL; + return (-1); + } + + if (ctx->heap != NULL) + free(ctx->heap); + free(ctx); + + return (0); +} + +static int +heap_resize(heap_context ctx) { + void **new_heap; + + ctx->array_size += ctx->array_size_increment; + new_heap = (void **)realloc(ctx->heap, + (ctx->array_size) * (sizeof (void *))); + if (new_heap == NULL) { + errno = ENOMEM; + return (-1); + } + ctx->heap = new_heap; + return (0); +} + +static void +float_up(heap_context ctx, int i, void *elt) { + int p; + + for ( p = heap_parent(i); + i > 1 && ctx->higher_priority(elt, ctx->heap[p]); + i = p, p = heap_parent(i) ) { + ctx->heap[i] = ctx->heap[p]; + if (ctx->index != NULL) + (ctx->index)(ctx->heap[i], i); + } + ctx->heap[i] = elt; + if (ctx->index != NULL) + (ctx->index)(ctx->heap[i], i); +} + +static void +sink_down(heap_context ctx, int i, void *elt) { + int j, size, half_size; + + size = ctx->heap_size; + half_size = size / 2; + while (i <= half_size) { + /* find smallest of the (at most) two children */ + j = heap_left(i); + if (j < size && ctx->higher_priority(ctx->heap[j+1], + ctx->heap[j])) + j++; + if (ctx->higher_priority(elt, ctx->heap[j])) + break; + ctx->heap[i] = ctx->heap[j]; + if (ctx->index != NULL) + (ctx->index)(ctx->heap[i], i); + i = j; + } + ctx->heap[i] = elt; + if (ctx->index != NULL) + (ctx->index)(ctx->heap[i], i); +} + +int +heap_insert(heap_context ctx, void *elt) { + int i; + + if (ctx == NULL || elt == NULL) { + errno = EINVAL; + return (-1); + } + + i = ++ctx->heap_size; + if (ctx->heap_size >= ctx->array_size && heap_resize(ctx) < 0) + return (-1); + + float_up(ctx, i, elt); + + return (0); +} + +int +heap_delete(heap_context ctx, int i) { + void *elt; + int less; + + if (ctx == NULL || i < 1 || i > ctx->heap_size) { + errno = EINVAL; + return (-1); + } + + if (i == ctx->heap_size) { + ctx->heap_size--; + } else { + elt = ctx->heap[ctx->heap_size--]; + less = ctx->higher_priority(elt, ctx->heap[i]); + ctx->heap[i] = elt; + if (less) + float_up(ctx, i, ctx->heap[i]); + else + sink_down(ctx, i, ctx->heap[i]); + } + + return (0); +} + +int +heap_increased(heap_context ctx, int i) { + if (ctx == NULL || i < 1 || i > ctx->heap_size) { + errno = EINVAL; + return (-1); + } + + float_up(ctx, i, ctx->heap[i]); + + return (0); +} + +int +heap_decreased(heap_context ctx, int i) { + if (ctx == NULL || i < 1 || i > ctx->heap_size) { + errno = EINVAL; + return (-1); + } + + sink_down(ctx, i, ctx->heap[i]); + + return (0); +} + +void * +heap_element(heap_context ctx, int i) { + if (ctx == NULL || i < 1 || i > ctx->heap_size) { + errno = EINVAL; + return (NULL); + } + + return (ctx->heap[i]); +} + +int +heap_for_each(heap_context ctx, heap_for_each_func action, void *uap) { + int i; + + if (ctx == NULL || action == NULL) { + errno = EINVAL; + return (-1); + } + + for (i = 1; i <= ctx->heap_size; i++) + (action)(ctx->heap[i], uap); + return (0); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/isc/heap.mdoc b/contrib/bind-9.5.2/lib/bind/isc/heap.mdoc new file mode 100644 index 0000000000..332a6ec5d0 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/heap.mdoc @@ -0,0 +1,378 @@ +.\" $Id: heap.mdoc,v 1.3 2004/03/09 06:30:08 marka Exp $ +.\" +.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (c) 1997,1999 by Internet Software Consortium. +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND 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. +.\" +.Dd January 1, 1997 +.\"Os OPERATING_SYSTEM [version/release] +.Os BSD 4 +.Dt HEAP @SYSCALL_EXT@ +.Sh NAME +.Nm heap_new , +.Nm heap_free , +.Nm heap_insert , +.Nm heap_delete , +.Nm heap_increased , +.Nm heap_decreased , +.Nm heap_element , +.Nm heap_for_each +.Nd heap implementation of priority queues +.Sh SYNOPSIS +.Fd #include \&"heap.h\&" +.Ft heap_context +.Fn heap_new "heap_higher_priority_func higher_priority" \ +"heap_index_func index" "int array_size_increment" +.Ft int +.Fn heap_free "heap_context ctx" +.Ft int +.Fn heap_insert "heap_context ctx" "void *elt" +.Ft int +.Fn heap_delete "heap_context ctx" "int i" +.Ft int +.Fn heap_increased "heap_context ctx" "int i" +.Ft int +.Fn heap_decreased "heap_context ctx" "int i" +.Ft void * +.Fn heap_element "heap_context ctx" "int i" +.Ft int +.Fn heap_for_each "heap_context ctx" "heap_for_each_func action" "void *uap" +.Sh DESCRIPTION +These functions implement heap\-based priority queues. The user defines a +priority scheme, and provides a function for comparison of the priority +of heap elements +(see the description of the +.Ft heap_higher_priority_func +function pointer, below). +.Pp +Each of the functions depends upon the +.Ft heap_context +type, which is a pointer to a +.Ft struct heap_context +.Pq see Pa heap.h No for more information . +.Pp +The +.Pa heap.h +header file also defines the following set of function +function pointers: +.Bd -literal -offset indent +typedef int (*heap_higher_priority_func)(void *, void *); +typedef void (*heap_index_func)(void *, int); +typedef void (*heap_for_each_func)(void *, void *); +.Ed +.Pp +These are pointers to user-defined functions. +The +.Ft heap_higher_priority_func +type is a pointer to a function which compares two +different heap (queue) elements and returns an +.Ft int +which answers the question, "Does the first queue element +have a higher priority than the second?" In other words, +a function pointer of this type +.Em must +return a number greater than zero +if the element indicated by the first argument is of a higher priority than +that indicated by the second element, and zero otherwise. +.Pp +The other two function pointers are documented in the descriptions +of +.Fn heap_new +.Pq Va heap_index_func +and +.Fn heap_for_each +.Pq Va heap_for_each_func , +below. +.Pp +The function +.Fn heap_new +initializes a +.Ft struct heap_context +and returns a pointer to it. The +.Fa higher_priority +function pointer +.Em must +be +.No non\- Ns Dv NULL . +As explained above, this refers to a +function supplied by the user which compares the priority of two different +queue or heap elements; see above for more information. +The second argument, +.Fa index , +is a pointer to a user-defined function whose arguments are +a heap element and its index in the heap. +.Fa Index +is intended to provide the user a means of knowing the internal index +of an element in the heap while maintaining the opacity of the implementation; +since the user has to know the actual indexes of heap elements in order to use, +e.g., +.Fn heap_delete +or +.Fn heap_element , +the user +.Fa index +function could store the index in the heap element, itself. If +.Fa index +is +.No non\- Ns Dv NULL , +then it is called +.Em whenever +the index of an element changes, allowing the user to stay up\-to\-date +with index changes. +The last argument, +.Fa array_size_increment +will be used, as its name suggests, by +.Xr malloc 3 +or +.Xr realloc 3 +to increment the array which implements the heap; if zero, a default value +will be used. +.Pp +The +.Fn heap_free +function frees the given +.Ft heap_context +argument +.Pq Fa ctx , +which also frees the entire +.Nm heap , +if it is +.No non\- Ns Dv NULL . +The argument +.Fa ctx +should be +.No non\- Ns Dv NULL . +.Pp +The +.Fn heap_insert +function is used to insert the new heap element +.Fa elt +into the appropriate place (priority\-wise) in the +.Ft heap +indicated by +.Fa ctx +(a pointer to a +.Ft heap_context ) . +If +.No non\- Ns Dv NULL , +the user-defined +.Ft higher_priority +function pointer associated with the indicated +.Nm heap +is used to determine that +.Dq appropriate place ; +the highest\-priority elements are at the front of the queue (top of +the heap). +(See the description of +.Fn heap_new , +above, for more information.) +.Pp +The function +.Fn heap_delete +is used to delete the +.Fa i\- Ns th +element of the queue (heap), and fixing up the queue (heap) from that +element onward via the priority as determined by the user function +pointed to by +.Ft higher_priority +function pointer +(see description of +.Fn heap_new , +above). +.Pp +.Fn heap_increased +.Pp +.Fn heap_decreased +.Pp +The +.Fn heap_element +function returns the +.Fa i\- Ns th +element of the queue/heap indicated by +.Fa ctx , +if possible. +.Pp +The +.Fn heap_for_each +function provides a mechanism for the user to increment through the entire +queue (heap) and perform some +.Fa action +upon each of the queue elements. This +.Fa action +is pointer to a user\-defined function with two arguments, the first of +which should be interpreted by the user's function as a heap element. The +second value passed to the user function is just the +.Fa uap +argument to +.Fn heap_for_each ; +this allows the user to specify additional arguments, if necessary, to +the function pointed to by +.Fa action . +.\" The following requests should be uncommented and +.\" used where appropriate. This next request is +.\" for sections 2 and 3 function return values only. +.Sh RETURN VALUES +.Bl -tag -width "heap_decreased()" +.It Fn heap_new +.Dv NULL +if unable to +.Xr malloc 3 +a +.Ft struct heap_context +or if the +.Fa higher_priority +function pointer is +.Dv NULL ; +otherwise, a valid +.Ft heap_context +.Ns . +.It Fn heap_free +-1 if +.Fa ctx +is +.Dv NULL +(with +.Va errno +set to +.Dv EINVAL ) ; +otherwise, 0. +.It Fn heap_insert +-1 +if either +.Fa ctx +or +.Fa elt +is +.Dv NULL , +or if an attempt to +.Xr malloc 3 +or +.Xr realloc 3 +the heap array fails (with +.Va errno +set to +.Dv EINVAL +or +.Dv ENOMEM , +respectively). +Otherwise, 0. +.It Fn heap_delete +-1 if +.Fa ctx +is +.Dv NULL +or +.Fa i +is out\-of\-range (with +.Va errno +set to +.Dv EINVAL ) ; +0 otherwise. +.It Fn heap_increased +As for +.Fn heap_delete . +.It Fn heap_decreased +As for +.Fn heap_delete . +.It Fn heap_element +NULL if +.Fa ctx +is +.Dv NULL +or +.Fa i +out\-of-bounds (with +.Va errno +set to +.Dv EINVAL ) ; +otherwise, a pointer to the +.Fa i\- Ns th +queue element. +.It Fn heap_for_each +-1 if either +.Fa ctx +or +.Fa action +is +.Dv NULL +(with +.Va errno +set to +.Dv EINVAL ) ; +0 otherwise. +.El +.\" This next request is for sections 1, 6, 7 & 8 only +.\" .Sh ENVIRONMENT +.Sh FILES +.Bl -tag -width "heap.h000" +.It Pa heap.h + heap library header file +.El +.\" .Sh EXAMPLES +.\" This next request is for sections 1, 6, 7 & 8 only +.\" (command return values (to shell) and +.\" fprintf/stderr type diagnostics) +.Sh DIAGNOSTICS +Please refer to +.Sx RETURN VALUES . +.\" The next request is for sections 2 and 3 error +.\" and signal handling only. +.Sh ERRORS +The variable +.Va errno +is set by +.Fn heap_free , +.Fn heap_insert , +.Fn heap_delete , +.Fn heap_increased , +and +.Fn heap_decreased +under the conditions of invalid input +.Pq Dv EINVAL +or lack of memory +.Pq Dv ENOMEM ; +please refer to +.Sx RETURN VALUES . +.Sh SEE ALSO +.Xr malloc 3 , +.Xr realloc 3 . +.Rs +.%A Cormen +.%A Leiserson +.%A Rivest +.%B Introduction to Algorithms +.%Q "MIT Press / McGraw Hill" +.%D 1990 +.%O ISBN 0\-262\-03141\-8 +.%P chapter 7 +.Re +.Rs +.%A Sedgewick +.%B Algorithms, 2nd ed'n +.%Q Addison\-Wesley +.%D 1988 +.%O ISBN 0\-201\-06673\-4 +.%P chapter 11 +.Re +.\" .Sh STANDARDS +.\" .Sh HISTORY +.Sh AUTHORS +The +.Nm heap +library was implemented by Bob Halley (halley@vix.com) of Vixie Enterprises, +Inc., for the Internet Software consortium, and was adapted from +the two books listed in the +.Sx SEE ALSO +section, above. +.\" .Sh BUGS diff --git a/contrib/bind-9.5.2/lib/bind/isc/hex.c b/contrib/bind-9.5.2/lib/bind/isc/hex.c new file mode 100644 index 0000000000..e43be4f3b5 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/hex.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 2001 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#include +#include +#include +#include +#include +#include + +static const char hex[17] = "0123456789abcdef"; + +int +isc_gethexstring(unsigned char *buf, size_t len, int count, FILE *fp, + int *multiline) +{ + int c, n; + unsigned char x; + char *s; + int result = count; + + x = 0; /*%< silence compiler */ + n = 0; + while (count > 0) { + c = fgetc(fp); + + if ((c == EOF) || + (c == '\n' && !*multiline) || + (c == '(' && *multiline) || + (c == ')' && !*multiline)) + goto formerr; + /* comment */ + if (c == ';') { + do { + c = fgetc(fp); + } while (c != EOF && c != '\n'); + if (c == '\n' && *multiline) + continue; + goto formerr; + } + /* white space */ + if (c == ' ' || c == '\t' || c == '\n' || c == '\r') + continue; + /* multiline */ + if ('(' == c || c == ')') { + *multiline = (c == '(' /*)*/); + continue; + } + if ((s = strchr(hex, tolower(c))) == NULL) + goto formerr; + x = (x<<4) | (s - hex); + if (++n == 2) { + if (len > 0U) { + *buf++ = x; + len--; + } else + result = -1; + count--; + n = 0; + } + } + return (result); + + formerr: + if (c == '\n') + ungetc(c, fp); + return (-1); +} + +void +isc_puthexstring(FILE *fp, const unsigned char *buf, size_t buflen, + size_t len1, size_t len2, const char *sep) +{ + size_t i = 0; + + if (len1 < 4U) + len1 = 4; + if (len2 < 4U) + len2 = 4; + while (buflen > 0U) { + fputc(hex[(buf[0]>>4)&0xf], fp); + fputc(hex[buf[0]&0xf], fp); + i += 2; + buflen--; + buf++; + if (i >= len1 && sep != NULL) { + fputs(sep, fp); + i = 0; + len1 = len2; + } + } +} + +void +isc_tohex(const unsigned char *buf, size_t buflen, char *t) { + while (buflen > 0U) { + *t++ = hex[(buf[0]>>4)&0xf]; + *t++ = hex[buf[0]&0xf]; + buf++; + buflen--; + } + *t = '\0'; +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/isc/logging.c b/contrib/bind-9.5.2/lib/bind/isc/logging.c new file mode 100644 index 0000000000..313a6c80e0 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/logging.c @@ -0,0 +1,716 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: logging.c,v 1.7.672.1 2008/02/28 05:46:12 marka Exp $"; +#endif /* not lint */ + +#include "port_before.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "port_after.h" + +#include "logging_p.h" + +static const int syslog_priority[] = { LOG_DEBUG, LOG_INFO, LOG_NOTICE, + LOG_WARNING, LOG_ERR, LOG_CRIT }; + +static const char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + +static const char *level_text[] = { + "info: ", "notice: ", "warning: ", "error: ", "critical: " +}; + +static void +version_rename(log_channel chan) { + unsigned int ver; + char old_name[PATH_MAX+1]; + char new_name[PATH_MAX+1]; + + ver = chan->out.file.versions; + if (ver < 1) + return; + if (ver > LOG_MAX_VERSIONS) + ver = LOG_MAX_VERSIONS; + /* + * Need to have room for '.nn' (XXX assumes LOG_MAX_VERSIONS < 100) + */ + if (strlen(chan->out.file.name) > (size_t)(PATH_MAX-3)) + return; + for (ver--; ver > 0; ver--) { + sprintf(old_name, "%s.%d", chan->out.file.name, ver-1); + sprintf(new_name, "%s.%d", chan->out.file.name, ver); + (void)isc_movefile(old_name, new_name); + } + sprintf(new_name, "%s.0", chan->out.file.name); + (void)isc_movefile(chan->out.file.name, new_name); +} + +FILE * +log_open_stream(log_channel chan) { + FILE *stream; + int fd, flags; + struct stat sb; + int regular; + + if (chan == NULL || chan->type != log_file) { + errno = EINVAL; + return (NULL); + } + + /* + * Don't open already open streams + */ + if (chan->out.file.stream != NULL) + return (chan->out.file.stream); + + if (stat(chan->out.file.name, &sb) < 0) { + if (errno != ENOENT) { + syslog(LOG_ERR, + "log_open_stream: stat of %s failed: %s", + chan->out.file.name, strerror(errno)); + chan->flags |= LOG_CHANNEL_BROKEN; + return (NULL); + } + regular = 1; + } else + regular = (sb.st_mode & S_IFREG); + + if (chan->out.file.versions) { + if (!regular) { + syslog(LOG_ERR, + "log_open_stream: want versions but %s isn't a regular file", + chan->out.file.name); + chan->flags |= LOG_CHANNEL_BROKEN; + errno = EINVAL; + return (NULL); + } + } + + flags = O_WRONLY|O_CREAT|O_APPEND; + + if ((chan->flags & LOG_TRUNCATE) != 0) { + if (regular) { + (void)unlink(chan->out.file.name); + flags |= O_EXCL; + } else { + syslog(LOG_ERR, + "log_open_stream: want truncation but %s isn't a regular file", + chan->out.file.name); + chan->flags |= LOG_CHANNEL_BROKEN; + errno = EINVAL; + return (NULL); + } + } + + fd = open(chan->out.file.name, flags, + S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + if (fd < 0) { + syslog(LOG_ERR, "log_open_stream: open(%s) failed: %s", + chan->out.file.name, strerror(errno)); + chan->flags |= LOG_CHANNEL_BROKEN; + return (NULL); + } + stream = fdopen(fd, "a"); + if (stream == NULL) { + syslog(LOG_ERR, "log_open_stream: fdopen() failed"); + chan->flags |= LOG_CHANNEL_BROKEN; + return (NULL); + } + (void) fchown(fd, chan->out.file.owner, chan->out.file.group); + + chan->out.file.stream = stream; + return (stream); +} + +int +log_close_stream(log_channel chan) { + FILE *stream; + + if (chan == NULL || chan->type != log_file) { + errno = EINVAL; + return (0); + } + stream = chan->out.file.stream; + chan->out.file.stream = NULL; + if (stream != NULL && fclose(stream) == EOF) + return (-1); + return (0); +} + +void +log_close_debug_channels(log_context lc) { + log_channel_list lcl; + int i; + + for (i = 0; i < lc->num_categories; i++) + for (lcl = lc->categories[i]; lcl != NULL; lcl = lcl->next) + if (lcl->channel->type == log_file && + lcl->channel->out.file.stream != NULL && + lcl->channel->flags & LOG_REQUIRE_DEBUG) + (void)log_close_stream(lcl->channel); +} + +FILE * +log_get_stream(log_channel chan) { + if (chan == NULL || chan->type != log_file) { + errno = EINVAL; + return (NULL); + } + return (chan->out.file.stream); +} + +char * +log_get_filename(log_channel chan) { + if (chan == NULL || chan->type != log_file) { + errno = EINVAL; + return (NULL); + } + return (chan->out.file.name); +} + +int +log_check_channel(log_context lc, int level, log_channel chan) { + int debugging, chan_level; + + REQUIRE(lc != NULL); + + debugging = ((lc->flags & LOG_OPTION_DEBUG) != 0); + + /* + * If not debugging, short circuit debugging messages very early. + */ + if (level > 0 && !debugging) + return (0); + + if ((chan->flags & (LOG_CHANNEL_BROKEN|LOG_CHANNEL_OFF)) != 0) + return (0); + + /* Some channels only log when debugging is on. */ + if ((chan->flags & LOG_REQUIRE_DEBUG) && !debugging) + return (0); + + /* Some channels use the global level. */ + if ((chan->flags & LOG_USE_CONTEXT_LEVEL) != 0) { + chan_level = lc->level; + } else + chan_level = chan->level; + + if (level > chan_level) + return (0); + + return (1); +} + +int +log_check(log_context lc, int category, int level) { + log_channel_list lcl; + int debugging; + + REQUIRE(lc != NULL); + + debugging = ((lc->flags & LOG_OPTION_DEBUG) != 0); + + /* + * If not debugging, short circuit debugging messages very early. + */ + if (level > 0 && !debugging) + return (0); + + if (category < 0 || category > lc->num_categories) + category = 0; /*%< use default */ + lcl = lc->categories[category]; + if (lcl == NULL) { + category = 0; + lcl = lc->categories[0]; + } + + for ( /* nothing */; lcl != NULL; lcl = lcl->next) { + if (log_check_channel(lc, level, lcl->channel)) + return (1); + } + return (0); +} + +void +log_vwrite(log_context lc, int category, int level, const char *format, + va_list args) { + log_channel_list lcl; + int pri, debugging, did_vsprintf = 0; + int original_category; + FILE *stream; + log_channel chan; + struct timeval tv; + struct tm *local_tm; +#ifdef HAVE_TIME_R + struct tm tm_tmp; +#endif + time_t tt; + const char *category_name; + const char *level_str; + char time_buf[256]; + char level_buf[256]; + + REQUIRE(lc != NULL); + + debugging = (lc->flags & LOG_OPTION_DEBUG); + + /* + * If not debugging, short circuit debugging messages very early. + */ + if (level > 0 && !debugging) + return; + + if (category < 0 || category > lc->num_categories) + category = 0; /*%< use default */ + original_category = category; + lcl = lc->categories[category]; + if (lcl == NULL) { + category = 0; + lcl = lc->categories[0]; + } + + /* + * Get the current time and format it. + */ + time_buf[0]='\0'; + if (gettimeofday(&tv, NULL) < 0) { + syslog(LOG_INFO, "gettimeofday failed in log_vwrite()"); + } else { + tt = tv.tv_sec; +#ifdef HAVE_TIME_R + local_tm = localtime_r(&tt, &tm_tmp); +#else + local_tm = localtime(&tt); +#endif + if (local_tm != NULL) { + sprintf(time_buf, "%02d-%s-%4d %02d:%02d:%02d.%03ld ", + local_tm->tm_mday, months[local_tm->tm_mon], + local_tm->tm_year+1900, local_tm->tm_hour, + local_tm->tm_min, local_tm->tm_sec, + (long)tv.tv_usec/1000); + } + } + + /* + * Make a string representation of the current category and level + */ + + if (lc->category_names != NULL && + lc->category_names[original_category] != NULL) + category_name = lc->category_names[original_category]; + else + category_name = ""; + + if (level >= log_critical) { + if (level >= 0) { + sprintf(level_buf, "debug %d: ", level); + level_str = level_buf; + } else + level_str = level_text[-level-1]; + } else { + sprintf(level_buf, "level %d: ", level); + level_str = level_buf; + } + + /* + * Write the message to channels. + */ + for ( /* nothing */; lcl != NULL; lcl = lcl->next) { + chan = lcl->channel; + + if (!log_check_channel(lc, level, chan)) + continue; + + if (!did_vsprintf) { + (void)vsprintf(lc->buffer, format, args); + if (strlen(lc->buffer) > (size_t)LOG_BUFFER_SIZE) { + syslog(LOG_CRIT, + "memory overrun in log_vwrite()"); + exit(1); + } + did_vsprintf = 1; + } + + switch (chan->type) { + case log_syslog: + if (level >= log_critical) + pri = (level >= 0) ? 0 : -level; + else + pri = -log_critical; + syslog(chan->out.facility|syslog_priority[pri], + "%s%s%s%s", + (chan->flags & LOG_TIMESTAMP) ? time_buf : "", + (chan->flags & LOG_PRINT_CATEGORY) ? + category_name : "", + (chan->flags & LOG_PRINT_LEVEL) ? + level_str : "", + lc->buffer); + break; + case log_file: + stream = chan->out.file.stream; + if (stream == NULL) { + stream = log_open_stream(chan); + if (stream == NULL) + break; + } + if (chan->out.file.max_size != ULONG_MAX) { + long pos; + + pos = ftell(stream); + if (pos >= 0 && + (unsigned long)pos > + chan->out.file.max_size) { + /* + * try to roll over the log files, + * ignoring all all return codes + * except the open (we don't want + * to write any more anyway) + */ + log_close_stream(chan); + version_rename(chan); + stream = log_open_stream(chan); + if (stream == NULL) + break; + } + } + fprintf(stream, "%s%s%s%s\n", + (chan->flags & LOG_TIMESTAMP) ? time_buf : "", + (chan->flags & LOG_PRINT_CATEGORY) ? + category_name : "", + (chan->flags & LOG_PRINT_LEVEL) ? + level_str : "", + lc->buffer); + fflush(stream); + break; + case log_null: + break; + default: + syslog(LOG_ERR, + "unknown channel type in log_vwrite()"); + } + } +} + +void +log_write(log_context lc, int category, int level, const char *format, ...) { + va_list args; + + va_start(args, format); + log_vwrite(lc, category, level, format, args); + va_end(args); +} + +/*% + * Functions to create, set, or destroy contexts + */ + +int +log_new_context(int num_categories, char **category_names, log_context *lc) { + log_context nlc; + + nlc = memget(sizeof (struct log_context)); + if (nlc == NULL) { + errno = ENOMEM; + return (-1); + } + nlc->num_categories = num_categories; + nlc->category_names = category_names; + nlc->categories = memget(num_categories * sizeof (log_channel_list)); + if (nlc->categories == NULL) { + memput(nlc, sizeof (struct log_context)); + errno = ENOMEM; + return (-1); + } + memset(nlc->categories, '\0', + num_categories * sizeof (log_channel_list)); + nlc->flags = 0U; + nlc->level = 0; + *lc = nlc; + return (0); +} + +void +log_free_context(log_context lc) { + log_channel_list lcl, lcl_next; + log_channel chan; + int i; + + REQUIRE(lc != NULL); + + for (i = 0; i < lc->num_categories; i++) + for (lcl = lc->categories[i]; lcl != NULL; lcl = lcl_next) { + lcl_next = lcl->next; + chan = lcl->channel; + (void)log_free_channel(chan); + memput(lcl, sizeof (struct log_channel_list)); + } + memput(lc->categories, + lc->num_categories * sizeof (log_channel_list)); + memput(lc, sizeof (struct log_context)); +} + +int +log_add_channel(log_context lc, int category, log_channel chan) { + log_channel_list lcl; + + if (lc == NULL || category < 0 || category >= lc->num_categories) { + errno = EINVAL; + return (-1); + } + + lcl = memget(sizeof (struct log_channel_list)); + if (lcl == NULL) { + errno = ENOMEM; + return(-1); + } + lcl->channel = chan; + lcl->next = lc->categories[category]; + lc->categories[category] = lcl; + chan->references++; + return (0); +} + +int +log_remove_channel(log_context lc, int category, log_channel chan) { + log_channel_list lcl, prev_lcl, next_lcl; + int found = 0; + + if (lc == NULL || category < 0 || category >= lc->num_categories) { + errno = EINVAL; + return (-1); + } + + for (prev_lcl = NULL, lcl = lc->categories[category]; + lcl != NULL; + lcl = next_lcl) { + next_lcl = lcl->next; + if (lcl->channel == chan) { + log_free_channel(chan); + if (prev_lcl != NULL) + prev_lcl->next = next_lcl; + else + lc->categories[category] = next_lcl; + memput(lcl, sizeof (struct log_channel_list)); + /* + * We just set found instead of returning because + * the channel might be on the list more than once. + */ + found = 1; + } else + prev_lcl = lcl; + } + if (!found) { + errno = ENOENT; + return (-1); + } + return (0); +} + +int +log_option(log_context lc, int option, int value) { + if (lc == NULL) { + errno = EINVAL; + return (-1); + } + switch (option) { + case LOG_OPTION_DEBUG: + if (value) + lc->flags |= option; + else + lc->flags &= ~option; + break; + case LOG_OPTION_LEVEL: + lc->level = value; + break; + default: + errno = EINVAL; + return (-1); + } + return (0); +} + +int +log_category_is_active(log_context lc, int category) { + if (lc == NULL) { + errno = EINVAL; + return (-1); + } + if (category >= 0 && category < lc->num_categories && + lc->categories[category] != NULL) + return (1); + return (0); +} + +log_channel +log_new_syslog_channel(unsigned int flags, int level, int facility) { + log_channel chan; + + chan = memget(sizeof (struct log_channel)); + if (chan == NULL) { + errno = ENOMEM; + return (NULL); + } + chan->type = log_syslog; + chan->flags = flags; + chan->level = level; + chan->out.facility = facility; + chan->references = 0; + return (chan); +} + +log_channel +log_new_file_channel(unsigned int flags, int level, + const char *name, FILE *stream, unsigned int versions, + unsigned long max_size) { + log_channel chan; + + chan = memget(sizeof (struct log_channel)); + if (chan == NULL) { + errno = ENOMEM; + return (NULL); + } + chan->type = log_file; + chan->flags = flags; + chan->level = level; + if (name != NULL) { + size_t len; + + len = strlen(name); + /* + * Quantize length to a multiple of 256. There's space for the + * NUL, since if len is a multiple of 256, the size chosen will + * be the next multiple. + */ + chan->out.file.name_size = ((len / 256) + 1) * 256; + chan->out.file.name = memget(chan->out.file.name_size); + if (chan->out.file.name == NULL) { + memput(chan, sizeof (struct log_channel)); + errno = ENOMEM; + return (NULL); + } + /* This is safe. */ + strcpy(chan->out.file.name, name); + } else { + chan->out.file.name_size = 0; + chan->out.file.name = NULL; + } + chan->out.file.stream = stream; + chan->out.file.versions = versions; + chan->out.file.max_size = max_size; + chan->out.file.owner = getuid(); + chan->out.file.group = getgid(); + chan->references = 0; + return (chan); +} + +int +log_set_file_owner(log_channel chan, uid_t owner, gid_t group) { + if (chan->type != log_file) { + errno = EBADF; + return (-1); + } + chan->out.file.owner = owner; + chan->out.file.group = group; + return (0); +} + +log_channel +log_new_null_channel() { + log_channel chan; + + chan = memget(sizeof (struct log_channel)); + if (chan == NULL) { + errno = ENOMEM; + return (NULL); + } + chan->type = log_null; + chan->flags = LOG_CHANNEL_OFF; + chan->level = log_info; + chan->references = 0; + return (chan); +} + +int +log_inc_references(log_channel chan) { + if (chan == NULL) { + errno = EINVAL; + return (-1); + } + chan->references++; + return (0); +} + +int +log_dec_references(log_channel chan) { + if (chan == NULL || chan->references <= 0) { + errno = EINVAL; + return (-1); + } + chan->references--; + return (0); +} + +log_channel_type +log_get_channel_type(log_channel chan) { + REQUIRE(chan != NULL); + + return (chan->type); +} + +int +log_free_channel(log_channel chan) { + if (chan == NULL || chan->references <= 0) { + errno = EINVAL; + return (-1); + } + chan->references--; + if (chan->references == 0) { + if (chan->type == log_file) { + if ((chan->flags & LOG_CLOSE_STREAM) && + chan->out.file.stream != NULL) + (void)fclose(chan->out.file.stream); + if (chan->out.file.name != NULL) + memput(chan->out.file.name, + chan->out.file.name_size); + } + memput(chan, sizeof (struct log_channel)); + } + return (0); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/isc/logging.mdoc b/contrib/bind-9.5.2/lib/bind/isc/logging.mdoc new file mode 100644 index 0000000000..98b2aed9c6 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/logging.mdoc @@ -0,0 +1,1056 @@ +.\" $Id: logging.mdoc,v 1.3 2004/03/09 06:30:08 marka Exp $ +.\" +.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (c) 1995-1999 by Internet Software Consortium +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND 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. +.\" +.\" The following six UNCOMMENTED lines are required. +.Dd January 1, 1996 +.\"Os OPERATING_SYSTEM [version/release] +.Os BSD 4 +.\"Dt DOCUMENT_TITLE [section number] [volume] +.Dt LOGGING @SYSCALL_EXT@ +.Sh NAME +.Nm log_open_stream , +.Nm log_close_stream , +.Nm log_get_stream , +.Nm log_get_filename , +.Nm log_vwrite , +.Nm log_write , +.Nm log_new_context , +.Nm log_free_context , +.Nm log_add_channel , +.Nm log_remove_channel , +.Nm log_option , +.Nm log_category_is_active , +.Nm log_new_syslog_channel , +.Nm log_new_file_channel , +.Nm log_set_file_owner , +.Nm log_new_null_channel , +.Nm log_inc_references , +.Nm log_dec_references , +.Nm log_free_channel +.Nd logging system +.Sh SYNOPSIS +.Fd #include +.Ft FILE * +.Fn log_open_stream "log_channel chan" +.Ft int +.Fn log_close_stream "log_channel chan" +.Ft FILE * +.Fn log_get_stream "log_channel chan" +.Ft char * +.Fn log_get_filename "log_channel chan" +.Ft void +.Fn log_vwrite "log_context lc" "int category" "int level" \ + "const char *format" va_list args" +.Ft void +.Fn log_write "log_context lc" "int category" "int level" \ + "const char *format" "..." +.Ft int +.Fn log_check_channel "log_context lc" "int level" "log_channel chan" +.Ft int +.Fn log_check "log_context lc" "int category" "int level" +.Ft int +.Fn log_new_context "int num_categories" "char **category_names" \ + "log_context *lc" +.Ft void +.Fn log_free_context "log_context lc" +.Ft int +.Fn log_add_channel "log_context lc" "int category" "log_channel chan" +.Ft int +.Fn log_remove_channel "log_context lc" "int category" "log_channel chan" +.Ft int +.Fn log_option "log_context lc" "int option" "int value" +.Ft int +.Fn log_category_is_active "log_context lc" "int category" +.Ft log_channel +.Fn log_new_syslog_channel "unsigned int flags" "int level" "int facility" +.Ft log_channel +.Fn log_new_file_channel "unsigned int flags" "int level" \ + "char *name" "FILE *stream" "unsigned int versions" \ + "unsigned long max_size" +.Ft int +.Fn log_set_file_owner "log_channel chan" "uid_t owner" "gid_t group" +.Ft log_channel +.Fn log_new_null_channel "void" +.Ft int +.Fn log_inc_references "log_channel chan" +.Ft int +.Fn log_dec_references "log_channel chan" +.Ft int +.Fn log_free_channel "log_channel chan" +.Sh DESCRIPTION +The +.Sy ISC +.Nm logging library +is flexible logging system which is based upon a set of concepts: +.Nm logging channels , +.Nm categories , +and +.Nm logging contexts . +.Pp +The basic building block is the +.Dq Nm logging channel , +which includes a +.Nm priority +(logging level), which type of logging is to occur, and other +flags and information associated with technical aspects of the logging. +The set of priorities which are supported is shown below, in the section +.Sx Message Priorities . +A priority sets a threshold for message logging; a logging channel will +.Em only +log those messages which are +.Em at least as important +as its priority indicates. (The fact that +.Dq more important +means +.Dq more negative , +under the current scheme, is an implementation detail; if a channel has +a priority of +.Dv log_error , +then it will +.Em not +log messages with the +.Dv log_warning +priority, but it +.Em will +log messages with the +.Dv log_error +or +.Dv log_critical +priority.) +.Pp +The +.Nm logging channel +also has an indication of the type of logging performed. Currently, +the supported +.Nm logging types +include (see also +.Sx Logging Types , +below): +.Bl -tag -width "log_syslog" -compact -offset indent +.It Dv log_syslog +for +.Xr syslog 3 Ns -style +logging +.It Dv log_file +for use of a file +.It Dv log_null +for +.Em no +logging +.El +A new logging channel is created by calling either +.Fn log_new_syslog_channel , +.Fn log_new_file_channel , +or +.Fn log_new_null_channel , +respectively. +When a channel is no longer to be used, it can be freed using +.Fn log_free_channel . +.Pp +Both +.Dv log_syslog +and +.Dv log_file +channel types can include more information; for instance, a +.Dv log_syslog Ns -type +channel allows the specification of a +.Xr syslog 3 Ns -style +.Dq facility , +and a +.Dv log_file Ns -type +channels allows the caller to set a maximum file size and number +of versions. (See +.Fn log_new_syslog_channel +or +.Fn log_new_file_channel , +below.) +Additionally, once a logging channel of type +.Dv log_file +is defined, the functions +.Fn log_open_stream +and +.Fn log_close_stream +can open or close the stream associated with the logging channel's logging +filename. The +.Fn log_get_stream +and +.Fn log_get_filename +functions return the stream or filename, respectively, of such a logging +channel. Also unique to logging channels of type +.Dv log_file +is the +.Fn log_set_file_owner +function, which tells the logging system what user and group ought to own +newly created files (which is only effective if the caller is privileged.) +.Pp +Callers provide +.Dq Nm categories , +determining both the number of such categories and any (optional) names. +Categories are like array indexes in C; if the caller declares +.Dq Va n +categories, then they are considered to run from 0 to +.Va n-1 ; +with this scheme, a category number would be invalid if it were negative or +greater than/equal to +.Va n . +Each category can have its own list of +.Nm logging channels +associated with it; we say that such a channel is +.Dq in +the particular category. +.Sy NOTE : +Individual logging channels can appear in more than one category. +.Pp +A +.Dq Nm logging context +is the set of all +.Nm logging channels +associated with the context's +.Nm categories ; +thus, a particular +.Nm category +scheme is associated with a particular +.Nm logging context . +.Sy NOTE : +A logging channel may appear in more than one logging context, and in +multiple categories within each logging context. +.Pp +Use +.Fn log_add_channel +and +.Fn log_remove_channel +to add or remove a logging channel to some category in a logging context. +To see if a given category in a logging context is being used, use the +Boolean test +.Fn log_category_is_active . +.Pp +A +.Nm logging context +can also have a +.Nm priority +(logging level) +and various flags associated with the whole context; in order to alter the +flags or change the priority of a context, use +.Fn log_option . +.Ss Message Priorities +Currently, five +.Nm priorities +(logging levels) are supported (they can also be found in the header file): +.Bd -literal -offset indent +#define log_critical (-5) +#define log_error (-4) +#define log_warning (-3) +#define log_notice (-2) +#define log_info (-1) +.Ed +.Pp +In the current implementation, logging messages which have a level greater +than 0 are considered to be debugging messages. +.Ss Logging Types +The three different +.Nm logging types +currently supported are different values of the enumerated type +.Ft log_output_type +(these are also listed in the header file): +.Bd -literal -offset indent +typedef enum { log_syslog, log_file, log_null } log_output_type; +.Ed +.Ss Logging Channel Flags +There are several flags which can be set on a logging channel; the flags +and their meanings are as follows (they are also found in the header file): +.Bl -tag -width "LOG_USE_CONTEXT_LEVEL " -offset indent +.It Dv LOG_CHANNEL_BROKEN +This is set only when some portion of +.Fn log_open_stream +fails: +.Xr open 2 +or +.Xr fdopen 3 +fail; +.Xr stat 2 +fails in a +.Dq bad +way; versioning or truncation is requested on a non-normal file. +.It Dv LOG_CHANNEL_OFF +This is set for channels opened by +.Fn log_new_null_channel . +.It Dv LOG_CLOSE_STREAM +If this flag is set, then +.Fn log_free_channel +will free a +.No non- Dv NULL +stream of a logging channel which is being +.Xr free 3 Ns -d +(if the logging channel is of type +.Dv log_file , +of course). +.It Dv LOG_PRINT_CATEGORY +If set, +.Fn log_vwrite +will insert the category name, if available, into logging messages which are +logged to channels of type +.Dv log_syslog +or +.Dv log_file . +.It Dv LOG_PRINT_LEVEL +If set, +.Fn log_vwrite +will insert a string identifying the message priority level into the +information logged to channels of type +.Dv log_syslog +or +.Dv log_file . +.It Dv LOG_REQUIRE_DEBUG +Only log debugging messages (i.e., those with a priority greater than zero). +.It Dv LOG_TIMESTAMP +If set, +.Fn log_vwrite +will insert a timestamp into logging messages which are logged to channels of +type +.Dv log_syslog +or +.Dv log_file . +.It Dv LOG_TRUNCATE +Truncate logging file when re-opened +.Fn ( log_open_stream +will +.Xr unlink 2 +the file and then +.Xr open 2 +a new file of the same name with the +.Dv O_EXCL +bit set). +.It Dv LOG_USE_CONTEXT_LEVEL +Use the logging context's priority or logging level, rather than the logging +channel's own priority. This can be useful for those channels which are +included in multiple logging contexts. +.El +.Ss FUNCTION DESCRIPTIONS +The function +.Fn log_open_stream +is for use with channels which log to a file; i.e., logging channels with a +.Va type +field set to +.Dq Dv log_file . +If the logging channel pointed to by +.Dq Fa chan +is valid, it attempts to open (and return) the stream associated with that +channel. If the stream is already opened, then it is returned; otherwise, +.Xr stat 2 +is used to test the filename for the stream. +.Pp +At this point, if the logging file is supposed to have different +.Va versions +(i.e., incremented version numbers; higher numbers indicate older versions +of the logging file). If so, then any existing versions are +.Xr rename 2 Ns -d +to have one version-number higher than previously, and the +.Dq current +filename for the stream is set to the +.Dq \&.0 +form of the name. Next, if the logging file is supposed to be truncated +(i.e., the +.Dv LOG_TRUNCATE +bit of the +.Va flags +field of the logging channel structure is set), then any file with the +.Dq current +filename for the stream is +.Xr unlink 2 Ns -d . +.Sy NOTE : +If the logging file is +.Em not +a regular file, and either of the above operations (version numbering +or truncation) is supposed to take place, a +.Dv NULL +file pointer is returned. +.Pp +Finally, the filename associated with the logging channel is +.Xr open 2 Ns -d +using the appropriate flags and a mode which sets the read/write permissions +for the user, group, and others. The file descriptor returned by +.Xr open 2 +is then passed to +.Xr fopen 3 , +with the append mode set, and the stream returned by this call is stored +in the +.Fa chan +structure and returned. +.Pp +If +.Fn log_open_stream +fails at any point, then the +.Dv LOG_CHANNEL_BROKEN +bit of the +.Va flags +field of the logging channel pointed to by +.Fa chan +is set, a +.Dv NULL +is returned, and +.Va errno +contains pertinent information. +.Pp +The +.Fn log_close_stream +function closes the stream associated with the logging channel pointed to by +.Dq Fa chan +(if +.Fa chan +is valid and the stream exists and can be closed properly by +.Xr fclose 3 ) . +The stream is set to +.Dv NULL +even if the call to +.Xr fclose 3 +fails. +.Pp +The function +.Fn log_get_stream +returns the stream associated with the logging channel pointed to by +.Dq Fa chan , +if it is +.No non- Ns Dv NULL +and specifies a logging channel which has a +.Dv FILE * +or stream associated with it. +.Pp +The +.Fn log_get_filename +function returns the name of the file associated with the logging channel +pointed to by +.Dq Fa chan , +if it is +.No non- Ns Dv NULL +and specifies a logging channel which has a file associated with it. +.Pp +The +.Fn log_vwrite +function performs the actual logging of a message to the various logging +channels of a logging context +.Fa lc . +The message consists of an +.Xr fprint 3 Ns -style +.Fa format +and its associated +.Fa args +(if any); it will be written to all logging channels in the given +.Fa category +which have a priority set to +.Fa level +or any +.Em less important +priority value. If the +.Fa category +is not valid or has no logging channels, then the category defaults to 0. +.Pp +There are a number of conditions under which a call to +.Fn log_vwrite +will not result in actually logging the message: if there is no logging channel +at even the default category (0), or if a given channel is either +.Dq broken +or +.Dq off +(i.e., its flags have +.Dv LOG_CHANNEL_BROKEN +or +.Dv LOG_CHANNEL_OFF +set, respectively), or if the logging channel channel is of type +.Dv log_null . +Additionally, if the logging channel's flag has +.Dv LOG_REQUIRE_DEBUG +set and the message is not a debugging message (i.e., has a level greater +than 0), then it will not be logged. +Finally, if the message's priority is less important than the +channel's logging level (the priority threshold), will not be logged. +.Sy NOTE : +If a logging channel's flag has +.Dv LOG_USE_CONTEXT_LEVEL +set, it will use the logging context's priority, rather than its own. +.Pp +If all of these hurdles are passed, then only +.Dv log_syslog +and +.Dv log_file +channels actually can have logging. For channels which use +.Xr syslog 3 , +the channel's +.Xr syslog 3 +facility is used in conjunction with a potentially modified form of the +message's priority level, since +.Xr syslog 3 +has its own system of priorities +.Pq Pa /usr/include/syslog.h . +All debug messages (priority >= 0) are mapped to +.Xr syslog 3 Ns 's +.Dv LOG_DEBUG +priority, all messages +.Dq more important +than +.Dv log_critical +are mapped to +.Dv LOG_CRIT , +and the priorities corresponding to the ones listed in the section +.Sx Message Priorities +are given the obvious corresponding +.Xr syslog 3 +priority. +.Pp +For +.Dv log_file +type logging channels, if the file size is greater than the maximum file +size, then no logging occurs. (The same thing happens if a +.Dv NULL +stream is encountered and +.Fn log_open_stream +fails to open the channel's stream.) +.Pp +For both logging to normal files and logging via +.Xr syslog 3 , +the value of the flags +.Dv LOG_TIMESTAMP , +.Dv LOG_PRINT_CATEGORY , +and +.Dv LOG_PRINT_LEVEL +are used in determining whether or not these items are included in the logged +information. +.Pp +The +.Fn log_write +function is merely a front-end to a call to +.Fn log_vwrite ; +see the description of that function, above, for more information. +.Pp +.Fn log_check +and +.Fn log_check_channel +are used to see if a contemplated logging call will actually generate any +output, which is useful when creating a log message involves non-trivial +work. +.Fn log_check +will return non-zero if a call to +.Fn log_vwrite +with the given +.Fa category +and +.Fa level +would generate output on any channels, and zero otherwise. +.Fn log_check_channel +will return non-zero if writing to the +.Fa chan +at the given +.Fa level +would generate output. +.Pp +The function +.Fn log_new_context +creates a new +.Nm logging context , +and stores this in the +.Dq Va opaque +field of the argument +.Dq Fa lc , +and opaque structure used internally. This new +.Nm context +will include the +.Dq Fa num_categories +and +.Dq Fa category_names +which are supplied; the latter can be +.Dv NULL . +.Sy NOTE : +Since +.Dq Fa category_names +is used directly, it +.Em must not +be freed by the caller, if it is +.No non- Ns Dv NULL . +The initial logging flags and priority are both set to zero. +.Pp +The +.Fn log_free_context +function is used to free the opaque structure +.Dq Va lc.opaque +and its components. +.Sy NOTE : +The +.Dq Va opaque +field of +.Dq Fa lc +.Em must +be +.No non- Ns Dv NULL . +For each of the various +.Dq categories +(indicated by the +.Dq Va num_categories +which were in the corresponding call to +.Fn log_new_context ) +associated with the given +.Nm logging context , +.Em all +of the +.Nm logging channels +are +.Xr free 3 Ns -d . +The opaque structure itself is then +.Xr free 3 Ns -d , +and +.Dq Va lc.opaque +is set to +.Dv NULL . +.Pp +.Sy NOTE : +The function +.Fn log_free_context +does +.Em not +free the memory associated with +.Fa category_names , +since the logging library did not allocate the memory for it, originally; +it was supplied in the call to +.Fn log_new_context . +.Pp +The function +.Fn log_add_channel +adds the +.Nm logging channel +.Dq Fa chan +to the list of logging channels in the given +.Fa category +of the +.Nm logging context +.Dq Fa lc . +No checking is performed to see whether or not +.Fa chan +is already present in the given +.Fa category , +so multiple instances in a single +.Fa category +can occur (but see +.Fn log_remove_channel , +below). +.Pp +The +.Fn log_remove_channel +function +removes +.Em all +occurrences of the +.Nm logging channel +.Dq Fa chan +from the list of logging channels in the given +.Fa category +of the +.Nm logging context +.Dq Fa lc . +It also attempts to free the channel by calling +.Fn log_free_channel +(see its description, below). +.Pp +The +.Fn log_option +function is used to change the +.Fa option +of the indicated logging context +.Fa lc +to the given +.Fa value . +The +.Fa option +can be either +.Dv LOG_OPTION_LEVEL +or +.Dv LOG_OPTION_DEBUG ; +in the first case, the log context's debugging level is reset to the +indicated level. If the +.Fa option +is +.Dv LOG_OPTION_DEBUG , +then a non-zero +.Fa value +results in setting the debug flag of the logging context, while a zero +.Fa value +means that the debug flag is reset. +.Pp +The +.Fn log_category_is_active +test returns a 1 if the given +.Fa category +of the indicated logging context +.Fa lc +has at least one logging channel, and 0, otherwise. +.Pp +The functions +.Fn log_new_syslog_channel , +.Fn log_new_file_channel , +and +.Fn log_new_null_channel +create a new channel of the type specified (thus, the difference in arguments); +the +.Dq Va type +field of the new +.Do +.Ft struct log_channel +.Dc +is always set to the appropriate value. +.Pp +The +.Fn log_new_syslog_channel +function +.Xr malloc 3 Ns -s +a new +.Ft struct log_channel +of +.Va type +.Dv log_syslog , +i.e., a logging channel which will use +.Xr syslog 3 . +The new structure is filled out with the +.Dq Fa flags , +.Dq Fa level , +and +.Dq Fa facility +which are given; the +.Va references +field is initialized to zero. +See +.Sx Logging Channel Flags +and +.Sx Message Priorities , +above, or the header file for information about acceptable values for +.Dq Fa flags , +and +.Dq Fa level . +The +.Dq Fa facility . +can be any valid +.Xr syslog 3 +facility; see the appropriate system header file or manpage for more +information. +.Pp +.Ft log_channel +.Fn log_new_file_channel "unsigned int flags" "int level" \ + "char *name" "FILE *stream" "unsigned int versions" \ + "unsigned long max_size" +.Pp +.Fn log_new_null_channel +.Pp +The functions +.Fn log_inc_references +and +.Fn log_dec_references +increment or decrements, respectively, the +.Va references +field of the logging channel pointed to by +.Dq Fa chan , +if it is a valid channel (and if the +.Va references +field is strictly positive, in the case of +.Fn log_dec_references ) . +These functions are meant to track changes in the number of different clients +which refer to the given logging channel. +.Pp +The +.Fn log_free_channel +function frees the +field of the logging channel pointed to by +.Dq Fa chan +if there are no more outstanding references to it. If the channel uses a file, +the stream is +.Xr fclose 3 Ns -d +(if the +.Dv LOG_CLOSE_STREAM +flag is set), and the filename, if +.No non- Ns Dv NULL , +is +.Xr free 3 Ns -d +before +.Dq Fa chan +is +.Xr free 3 Ns -d . +.Pp +.\" The following requests should be uncommented and +.\" used where appropriate. This next request is +.\" for sections 2 and 3 function return values only. +.Sh RETURN VALUES +.\" This next request is for sections 1, 6, 7 & 8 only +.Bl -tag -width "log_category_is_active()" +.It Fn log_open_stream +.Dv NULL +is returned under any of several error conditions: +a) if +.Dq Fa chan +is either +.Dv NULL +or a +.No non- Ns Dv log_file +channel +.Pq Va errno No is set to Dv EINVAL ; +b) if either versioning or truncation is requested for a non-normal file +.Pq Va errno No is set to Dv EINVAL ; +c) if any of +.Xr stat 2 , +.Xr open 2 , +or +.Xr fdopen 3 +fails +.Po +.Va errno +is set by the call which failed +.Pc . +If some value other than +.Dv NULL +is returned, then it is a valid logging stream (either newly-opened or +already-open). +.It Fn log_close_stream +-1 if the stream associated with +.Dq Fa chan +is +.No non- Ns Dv NULL +and the call to +.Xr fclose 3 +fails. +0 if successful or the logging channel pointed to by +.Dq Fa chan +is invalid (i.e., +.Dv NULL +or not a logging channel which has uses a file); in the latter case, +.Va errno +is set to +.Dv EINVAL . +.It Fn log_get_stream +.Dv NULL +under the same conditions as those under which +.Fn log_close_stream , +above, returns 0 (including the setting of +.Va errno ) . +Otherwise, the stream associated with the logging channel is returned. +.It Fn log_get_filename +.Dv NULL +under the same conditions as those under which +.Fn log_close_stream , +above, returns 0 (including the setting of +.Va errno ) . +Otherwise, the name of the file associated with the logging channel is +returned. +.It Fn log_new_context +-1 if +.Xr malloc 3 +fails +.Pq with Va errno No set to Dv ENOMEM . +Otherwise, 0, with +.Dq Va lc->opaque +containing the new structures and information. +.It Fn log_add_channel +-1 if +a) either +.Dq Va lc.opaque +is +.Dv NULL +or +.Fa category +is invalid (negative or greater than or equal to +.Va lcp->num_categories ) , +with +.Va errno +set to +.Dv EINVAL ; +b) +.Xr malloc 3 +fails +.Pq with Va errno No set to Dv ENOMEM . +Otherwise, 0. +.It Fn log_remove_channel +-1 if +a) either +.Dq Va lc.opaque +is +.Dv NULL +or +.Fa category +is invalid, as under failure condition a) for +.Fn log_add_channel , +above, including the setting of +.Va errno ; +b) no channel numbered +.Fa chan +is found in the logging context indicated by +.Fa lc +.Pq with Va errno No set to Dv ENOENT . +Otherwise, 0. +.It Fn log_option +-1 if +a) +.Dq Va lc.opaque +is +.Dv NULL , +b) +.Fa option +specifies an unknown logging option; +in either case, +.Va errno +is set to +.Dv EINVAL . +Otherwise, 0. +.It Fn log_category_is_active +-1 if +.Dq Va lc.opaque +is +.Dv NULL +.Pq with Va errno No set to Dv EINVAL ; +1 if the +.Fa category +number is valid and there are logging channels in this +.Fa category +within the indicated logging context; 0 if the +.Fa category +number is invalid or there are no logging channels in this +.Fa category +within the indicated logging context. +.It Fn log_new_syslog_channel +.Dv NULL +if +.Xr malloc 3 +fails +.Pq with Va errno No set to ENOMEM ; +otherwise, a valid +.Dv log_syslog Ns -type +.Ft log_channel . +.It Fn log_new_file_channel +.Dv NULL +if +.Xr malloc 3 +fails +.Pq with Va errno No set to ENOMEM ; +otherwise, a valid +.Dv log_file Ns -type +.Ft log_channel . +.It Fn log_new_null_channel +.Dv NULL +if +.Xr malloc 3 +fails +.Pq with Va errno No set to ENOMEM ; +otherwise, a valid +.Dv log_null Ns -type +.Ft log_channel . +.It Fn log_inc_references +-1 if +.Dq Fa chan +is +.Dv NULL +.Pq with Va errno set to Dv EINVAL . +Otherwise, 0. +.It Fn log_dec_references +-1 if +.Dq Fa chan +is +.Dv NULL +or its +.Va references +field is already <= 0 +.Pq with Va errno set to Dv EINVAL . +Otherwise, 0. +.It Fn log_free_channel +-1 under the same conditions as +.Fn log_dec_references , +above, including the setting of +.Va errno ; +0 otherwise. +.El +.\" .Sh ENVIRONMENT +.Sh FILES +.Bl -tag -width "isc/logging.h" +.It Pa isc/logging.h +include file for logging library +.It Pa syslog.h +.Xr syslog 3 Ns -style +priorities +.El +.\" .Sh EXAMPLES +.\" This next request is for sections 1, 6, 7 & 8 only +.\" (command return values (to shell) and +.\" fprintf/stderr type diagnostics) +.\" .Sh DIAGNOSTICS +.\" The next request is for sections 2 and 3 error +.\" and signal handling only. +.Sh ERRORS +This table shows which functions can return the indicated error in the +.Va errno +variable; see the +.Sx RETURN VALUES +section, above, for more information. +.Bl -tag -width "(any0other0value)0" +.It Dv EINVAL +.Fn log_open_stream , +.Fn log_close_stream , +.Fn log_get_stream , +.Fn log_get_filename , +.Fn log_add_channel , +.Fn log_remove_channel , +.Fn log_option , +.Fn log_category_is_active , +.Fn log_inc_references , +.Fn log_dec_references , +.Fn log_free_channel . +.It Dv ENOENT +.Fn log_remove_channel . +.It Dv ENOMEM +.Fn log_new_context , +.Fn log_add_channel , +.Fn log_new_syslog_channel , +.Fn log_new_file_channel , +.Fn log_new_null_channel . +.It (any other value) +returned via a pass-through of an error code from +.Xr stat 2 , +.Xr open 2 , +or +.Xr fdopen 3 , +which can occur in +.Fn log_open_stream +and functions which call it +.Pq currently, only Fn log_vwrite . +.El +.Pp +Additionally, +.Fn log_vwrite +and +.Fn log_free_context +will fail via +.Fn assert +if +.Dq Va lc.opaque +is +.Dv NULL . +The function +.Fn log_vwrite +can also exit with a critical error logged via +.Xr syslog 3 +indicating a memory overrun +.Sh SEE ALSO +.Xr @INDOT@named @SYS_OPS_EXT@ , +.Xr syslog 3 . +The HTML documentation includes a file, +.Pa logging.html , +which has more information about this logging system. +.\" .Sh STANDARDS +.\" .Sh HISTORY +.Sh AUTHORS +Bob Halley...TODO +.\" .Sh BUGS diff --git a/contrib/bind-9.5.2/lib/bind/isc/logging_p.h b/contrib/bind-9.5.2/lib/bind/isc/logging_p.h new file mode 100644 index 0000000000..5e6314f190 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/logging_p.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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 LOGGING_P_H +#define LOGGING_P_H + +typedef struct log_file_desc { + char *name; + size_t name_size; + FILE *stream; + unsigned int versions; + unsigned long max_size; + uid_t owner; + gid_t group; +} log_file_desc; + +typedef union log_output { + int facility; + log_file_desc file; +} log_output; + +struct log_channel { + int level; /*%< don't log messages > level */ + log_channel_type type; + log_output out; + unsigned int flags; + int references; +}; + +typedef struct log_channel_list { + log_channel channel; + struct log_channel_list *next; +} *log_channel_list; + +#define LOG_BUFFER_SIZE 20480 + +struct log_context { + int num_categories; + char **category_names; + log_channel_list *categories; + int flags; + int level; + char buffer[LOG_BUFFER_SIZE]; +}; + +#endif /* !LOGGING_P_H */ +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/isc/memcluster.c b/contrib/bind-9.5.2/lib/bind/isc/memcluster.c new file mode 100644 index 0000000000..515793fd6a --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/memcluster.c @@ -0,0 +1,588 @@ +/* + * Copyright (c) 2005 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1997,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + + +/* When this symbol is defined allocations via memget are made slightly + bigger and some debugging info stuck before and after the region given + back to the caller. */ +/* #define DEBUGGING_MEMCLUSTER */ +#define MEMCLUSTER_ATEND + + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: memcluster.c,v 1.11 2006/08/30 23:34:38 marka Exp $"; +#endif /* not lint */ + +#include "port_before.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#ifdef MEMCLUSTER_RECORD +#ifndef DEBUGGING_MEMCLUSTER +#define DEBUGGING_MEMCLUSTER +#endif +#endif + +#define DEF_MAX_SIZE 1100 +#define DEF_MEM_TARGET 4096 + +typedef u_int32_t fence_t; + +typedef struct { + void * next; +#if defined(DEBUGGING_MEMCLUSTER) +#if defined(MEMCLUSTER_RECORD) + const char * file; + int line; +#endif + size_t size; + fence_t fencepost; +#endif +} memcluster_element; + +#define SMALL_SIZE_LIMIT sizeof(memcluster_element) +#define P_SIZE sizeof(void *) +#define FRONT_FENCEPOST 0xfebafeba +#define BACK_FENCEPOST 0xabefabef +#define FENCEPOST_SIZE 4 + +#ifndef MEMCLUSTER_LITTLE_MALLOC +#define MEMCLUSTER_BIG_MALLOC 1 +#define NUM_BASIC_BLOCKS 64 +#endif + +struct stats { + u_long gets; + u_long totalgets; + u_long blocks; + u_long freefrags; +}; + +#ifdef DO_PTHREADS +#include +static pthread_mutex_t memlock = PTHREAD_MUTEX_INITIALIZER; +#define MEMLOCK (void)pthread_mutex_lock(&memlock) +#define MEMUNLOCK (void)pthread_mutex_unlock(&memlock) +#else +/* + * Catch bad lock usage in non threaded build. + */ +static unsigned int memlock = 0; +#define MEMLOCK do { INSIST(memlock == 0); memlock = 1; } while (0) +#define MEMUNLOCK do { INSIST(memlock == 1); memlock = 0; } while (0) +#endif /* DO_PTHEADS */ + +/* Private data. */ + +static size_t max_size; +static size_t mem_target; +#ifndef MEMCLUSTER_BIG_MALLOC +static size_t mem_target_half; +static size_t mem_target_fudge; +#endif +static memcluster_element ** freelists; +#ifdef MEMCLUSTER_RECORD +static memcluster_element ** activelists; +#endif +#ifdef MEMCLUSTER_BIG_MALLOC +static memcluster_element * basic_blocks; +#endif +static struct stats * stats; + +/* Forward. */ + +static size_t quantize(size_t); +#if defined(DEBUGGING_MEMCLUSTER) +static void check(unsigned char *, int, size_t); +#endif + +/* Public. */ + +int +meminit(size_t init_max_size, size_t target_size) { + +#if defined(DEBUGGING_MEMCLUSTER) + INSIST(sizeof(fence_t) == FENCEPOST_SIZE); +#endif + if (freelists != NULL) { + errno = EEXIST; + return (-1); + } + if (init_max_size == 0U) + max_size = DEF_MAX_SIZE; + else + max_size = init_max_size; + if (target_size == 0U) + mem_target = DEF_MEM_TARGET; + else + mem_target = target_size; +#ifndef MEMCLUSTER_BIG_MALLOC + mem_target_half = mem_target / 2; + mem_target_fudge = mem_target + mem_target / 4; +#endif + freelists = malloc(max_size * sizeof (memcluster_element *)); + stats = malloc((max_size+1) * sizeof (struct stats)); + if (freelists == NULL || stats == NULL) { + errno = ENOMEM; + return (-1); + } + memset(freelists, 0, + max_size * sizeof (memcluster_element *)); + memset(stats, 0, (max_size + 1) * sizeof (struct stats)); +#ifdef MEMCLUSTER_RECORD + activelists = malloc((max_size + 1) * sizeof (memcluster_element *)); + if (activelists == NULL) { + errno = ENOMEM; + return (-1); + } + memset(activelists, 0, + (max_size + 1) * sizeof (memcluster_element *)); +#endif +#ifdef MEMCLUSTER_BIG_MALLOC + basic_blocks = NULL; +#endif + return (0); +} + +void * +__memget(size_t size) { + return (__memget_record(size, NULL, 0)); +} + +void * +__memget_record(size_t size, const char *file, int line) { + size_t new_size = quantize(size); +#if defined(DEBUGGING_MEMCLUSTER) + memcluster_element *e; + char *p; + fence_t fp = BACK_FENCEPOST; +#endif + void *ret; + + MEMLOCK; + +#if !defined(MEMCLUSTER_RECORD) + UNUSED(file); + UNUSED(line); +#endif + if (freelists == NULL) { + if (meminit(0, 0) == -1) { + MEMUNLOCK; + return (NULL); + } + } + if (size == 0U) { + MEMUNLOCK; + errno = EINVAL; + return (NULL); + } + if (size >= max_size || new_size >= max_size) { + /* memget() was called on something beyond our upper limit. */ + stats[max_size].gets++; + stats[max_size].totalgets++; +#if defined(DEBUGGING_MEMCLUSTER) + e = malloc(new_size); + if (e == NULL) { + MEMUNLOCK; + errno = ENOMEM; + return (NULL); + } + e->next = NULL; + e->size = size; +#ifdef MEMCLUSTER_RECORD + e->file = file; + e->line = line; + e->next = activelists[max_size]; + activelists[max_size] = e; +#endif + MEMUNLOCK; + e->fencepost = FRONT_FENCEPOST; + p = (char *)e + sizeof *e + size; + memcpy(p, &fp, sizeof fp); + return ((char *)e + sizeof *e); +#else + MEMUNLOCK; + return (malloc(size)); +#endif + } + + /* + * If there are no blocks in the free list for this size, get a chunk + * of memory and then break it up into "new_size"-sized blocks, adding + * them to the free list. + */ + if (freelists[new_size] == NULL) { + int i, frags; + size_t total_size; + void *new; + char *curr, *next; + +#ifdef MEMCLUSTER_BIG_MALLOC + if (basic_blocks == NULL) { + new = malloc(NUM_BASIC_BLOCKS * mem_target); + if (new == NULL) { + MEMUNLOCK; + errno = ENOMEM; + return (NULL); + } + curr = new; + next = curr + mem_target; + for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) { + ((memcluster_element *)curr)->next = next; + curr = next; + next += mem_target; + } + /* + * curr is now pointing at the last block in the + * array. + */ + ((memcluster_element *)curr)->next = NULL; + basic_blocks = new; + } + total_size = mem_target; + new = basic_blocks; + basic_blocks = basic_blocks->next; +#else + if (new_size > mem_target_half) + total_size = mem_target_fudge; + else + total_size = mem_target; + new = malloc(total_size); + if (new == NULL) { + MEMUNLOCK; + errno = ENOMEM; + return (NULL); + } +#endif + frags = total_size / new_size; + stats[new_size].blocks++; + stats[new_size].freefrags += frags; + /* Set up a linked-list of blocks of size "new_size". */ + curr = new; + next = curr + new_size; + for (i = 0; i < (frags - 1); i++) { +#if defined (DEBUGGING_MEMCLUSTER) + memset(curr, 0xa5, new_size); +#endif + ((memcluster_element *)curr)->next = next; + curr = next; + next += new_size; + } + /* curr is now pointing at the last block in the array. */ +#if defined (DEBUGGING_MEMCLUSTER) + memset(curr, 0xa5, new_size); +#endif + ((memcluster_element *)curr)->next = freelists[new_size]; + freelists[new_size] = new; + } + + /* The free list uses the "rounded-up" size "new_size". */ +#if defined (DEBUGGING_MEMCLUSTER) + e = freelists[new_size]; + ret = (char *)e + sizeof *e; + /* + * Check to see if this buffer has been written to while on free list. + */ + check(ret, 0xa5, new_size - sizeof *e); + /* + * Mark memory we are returning. + */ + memset(ret, 0xe5, size); +#else + ret = freelists[new_size]; +#endif + freelists[new_size] = freelists[new_size]->next; +#if defined(DEBUGGING_MEMCLUSTER) + e->next = NULL; + e->size = size; + e->fencepost = FRONT_FENCEPOST; +#ifdef MEMCLUSTER_RECORD + e->file = file; + e->line = line; + e->next = activelists[size]; + activelists[size] = e; +#endif + p = (char *)e + sizeof *e + size; + memcpy(p, &fp, sizeof fp); +#endif + + /* + * The stats[] uses the _actual_ "size" requested by the + * caller, with the caveat (in the code above) that "size" >= the + * max. size (max_size) ends up getting recorded as a call to + * max_size. + */ + stats[size].gets++; + stats[size].totalgets++; + stats[new_size].freefrags--; + MEMUNLOCK; +#if defined(DEBUGGING_MEMCLUSTER) + return ((char *)e + sizeof *e); +#else + return (ret); +#endif +} + +/*% + * This is a call from an external caller, + * so we want to count this as a user "put". + */ +void +__memput(void *mem, size_t size) { + __memput_record(mem, size, NULL, 0); +} + +void +__memput_record(void *mem, size_t size, const char *file, int line) { + size_t new_size = quantize(size); +#if defined (DEBUGGING_MEMCLUSTER) + memcluster_element *e; + memcluster_element *el; +#ifdef MEMCLUSTER_RECORD + memcluster_element *prev; +#endif + fence_t fp; + char *p; +#endif + + MEMLOCK; + +#if !defined (MEMCLUSTER_RECORD) + UNUSED(file); + UNUSED(line); +#endif + + REQUIRE(freelists != NULL); + + if (size == 0U) { + MEMUNLOCK; + errno = EINVAL; + return; + } + +#if defined (DEBUGGING_MEMCLUSTER) + e = (memcluster_element *) ((char *)mem - sizeof *e); + INSIST(e->fencepost == FRONT_FENCEPOST); + INSIST(e->size == size); + p = (char *)e + sizeof *e + size; + memcpy(&fp, p, sizeof fp); + INSIST(fp == BACK_FENCEPOST); + INSIST(((u_long)mem % 4) == 0); +#ifdef MEMCLUSTER_RECORD + prev = NULL; + if (size == max_size || new_size >= max_size) + el = activelists[max_size]; + else + el = activelists[size]; + while (el != NULL && el != e) { + prev = el; + el = el->next; + } + INSIST(el != NULL); /*%< double free */ + if (prev == NULL) { + if (size == max_size || new_size >= max_size) + activelists[max_size] = el->next; + else + activelists[size] = el->next; + } else + prev->next = el->next; +#endif +#endif + + if (size == max_size || new_size >= max_size) { + /* memput() called on something beyond our upper limit */ +#if defined(DEBUGGING_MEMCLUSTER) + free(e); +#else + free(mem); +#endif + + INSIST(stats[max_size].gets != 0U); + stats[max_size].gets--; + MEMUNLOCK; + return; + } + + /* The free list uses the "rounded-up" size "new_size": */ +#if defined(DEBUGGING_MEMCLUSTER) + memset(mem, 0xa5, new_size - sizeof *e); /*%< catch write after free */ + e->size = 0; /*%< catch double memput() */ +#ifdef MEMCLUSTER_RECORD + e->file = file; + e->line = line; +#endif +#ifdef MEMCLUSTER_ATEND + e->next = NULL; + el = freelists[new_size]; + while (el != NULL && el->next != NULL) + el = el->next; + if (el) + el->next = e; + else + freelists[new_size] = e; +#else + e->next = freelists[new_size]; + freelists[new_size] = (void *)e; +#endif +#else + ((memcluster_element *)mem)->next = freelists[new_size]; + freelists[new_size] = (memcluster_element *)mem; +#endif + + /* + * The stats[] uses the _actual_ "size" requested by the + * caller, with the caveat (in the code above) that "size" >= the + * max. size (max_size) ends up getting recorded as a call to + * max_size. + */ + INSIST(stats[size].gets != 0U); + stats[size].gets--; + stats[new_size].freefrags++; + MEMUNLOCK; +} + +void * +__memget_debug(size_t size, const char *file, int line) { + void *ptr; + ptr = __memget_record(size, file, line); + fprintf(stderr, "%s:%d: memget(%lu) -> %p\n", file, line, + (u_long)size, ptr); + return (ptr); +} + +void +__memput_debug(void *ptr, size_t size, const char *file, int line) { + fprintf(stderr, "%s:%d: memput(%p, %lu)\n", file, line, ptr, + (u_long)size); + __memput_record(ptr, size, file, line); +} + +/*% + * Print the stats[] on the stream "out" with suitable formatting. + */ +void +memstats(FILE *out) { + size_t i; +#ifdef MEMCLUSTER_RECORD + memcluster_element *e; +#endif + + MEMLOCK; + + if (freelists == NULL) { + MEMUNLOCK; + return; + } + for (i = 1; i <= max_size; i++) { + const struct stats *s = &stats[i]; + + if (s->totalgets == 0U && s->gets == 0U) + continue; + fprintf(out, "%s%5lu: %11lu gets, %11lu rem", + (i == max_size) ? ">=" : " ", + (unsigned long)i, s->totalgets, s->gets); + if (s->blocks != 0U) + fprintf(out, " (%lu bl, %lu ff)", + s->blocks, s->freefrags); + fputc('\n', out); + } +#ifdef MEMCLUSTER_RECORD + fprintf(out, "Active Memory:\n"); + for (i = 1; i <= max_size; i++) { + if ((e = activelists[i]) != NULL) + while (e != NULL) { + fprintf(out, "%s:%d %p:%lu\n", + e->file != NULL ? e->file : + "", e->line, + (char *)e + sizeof *e, + (u_long)e->size); + e = e->next; + } + } +#endif + MEMUNLOCK; +} + +int +memactive(void) { + size_t i; + + if (stats == NULL) + return (0); + for (i = 1; i <= max_size; i++) + if (stats[i].gets != 0U) + return (1); + return (0); +} + +/* Private. */ + +/*% + * Round up size to a multiple of sizeof(void *). This guarantees that a + * block is at least sizeof void *, and that we won't violate alignment + * restrictions, both of which are needed to make lists of blocks. + */ +static size_t +quantize(size_t size) { + int remainder; + /* + * If there is no remainder for the integer division of + * + * (rightsize/P_SIZE) + * + * then we already have a good size; if not, then we need + * to round up the result in order to get a size big + * enough to satisfy the request _and_ aligned on P_SIZE boundaries. + */ + remainder = size % P_SIZE; + if (remainder != 0) + size += P_SIZE - remainder; +#if defined(DEBUGGING_MEMCLUSTER) + return (size + SMALL_SIZE_LIMIT + sizeof (int)); +#else + return (size); +#endif +} + +#if defined(DEBUGGING_MEMCLUSTER) +static void +check(unsigned char *a, int value, size_t len) { + size_t i; + for (i = 0; i < len; i++) + INSIST(a[i] == value); +} +#endif + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/isc/memcluster.mdoc b/contrib/bind-9.5.2/lib/bind/isc/memcluster.mdoc new file mode 100644 index 0000000000..20b39d0aee --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/memcluster.mdoc @@ -0,0 +1,376 @@ +.\" $Id: memcluster.mdoc,v 1.3 2004/03/09 06:30:08 marka Exp $ +.\" +.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (c) 1995-1999 by Internet Software Consortium +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND 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. +.\" +.\" The following six UNCOMMENTED lines are required. +.Dd Month day, year +.\"Os OPERATING_SYSTEM [version/release] +.Os BSD 4 +.\"Dt DOCUMENT_TITLE [section number] [volume] +.Dt MEMCLUSTER 3 +.Sh NAME +.Nm meminit , +.Nm memget , +.Nm memput , +.Nm memstats +.Nd memory allocation/deallocation system +.Sh SYNOPSIS +.Fd #include \& +.Ft void * +.Fn memget "size_t size" +.Ft void +.Fn memput "void *mem" "size_t size" +.Ft void +.Fn memstats "FILE *out" +.Sh DESCRIPTION +These functions access a memory management system which allows callers to not +fragment memory to the extent which can ordinarily occur through many random +calls to +.Xr malloc 3 . +Instead, +.Fn memget +gets a large contiguous chunk of blocks of the requested +.Fa size +and parcels out these blocks as requested. The symmetric call is +.Fn memput , +which callers use to return a piece of memory obtained from +.Fn memget . +Statistics about memory usage are returned by +.Fn memstats , +which prints a report on the stream +.Fa out . +.Ss INTERNALS +Internally, linked lists of free memory blocks are stored in an array. +The size of this array is determined by the value +.Dv MEM_FREECOUNT , +currently set to 1100. In general, for any requested blocksize +.Dq Fa size , +any free blocks will be stored on the linked list at that index. +No free lists are managed for blocks greater than or equal to +.Dv MEM_FREECOUNT +bytes; instead, calls to +.Xr malloc 3 +or +.Xr free 3 +are made, directly. +.Pp +Since the blocks are actually stored as linked lists, they must at least +be large enough to hold a pointer to the next block. This size, which is +.Dv SMALL_SIZE_LIMIT , +is currently defined as +.Bd -literal -offset indent +#define SMALL_SIZE_LIMIT sizeof(struct { void *next; }) +.Ed +.Pp +Both +.Fn memget +and +.Fn memput +enforce this limit; for example, any call to +.Fn memget +requesting a block smaller than +.Dv SMALL_SIZE_LIMIT +bytes will actually be considered to be of size +.Dv SMALL_SIZE_LIMIT +internally. (Such a caller request will be logged for +.Fn memstats +purposes using the caller-requested +.Fa size ; +see the discussion of +.Fn memstats , +below, for more information.) +.Pp +Additionally, the requested +.Fa size +will be adjusted so that when a large +.Xr malloc 3 Ns No -d +chunk of memory is broken up into a linked list, the blocks will all fall on +the correct memory alignment boundaries. Thus, one can conceptualize a call +which mentions +.Fa size +as resulting in a +.Fa new_size +which is used internally. +.Pp +In order to more efficiently allocate memory, there is a +.Dq target +size for calls to +.Xr malloc 3 . +It is given by the pre-defined value +.Dv MEM_TARGET , +which is currently 4096 bytes. +For any requested block +.Fa size , +enough memory is +.Xr malloc 3 Ns No -d +in order to fill up a block of about +.Dv MEM_TARGET +bytes. +.No [ Ns Sy NOTE : +For allocations larger than +.Dv MEM_TARGET Ns No /2 +bytes, there is a +.Dq fudge factor +introduced which boosts the target size by 25% of +.Dv MEM_TARGET . +This means that enough memory for two blocks +will actually be allocated for any +.Fa size +such that +.Pq Dv MEM_TARGET Ns No / 3 +.No < Fa size No < +.Pq Dv MEM_TARGET Ns No *5/8 , +provided that the value of +.Dv MEM_FREECOUNT +is at least as large as the upper limit shown above.] +.Pp +.Ss FUNCTION DESCRIPTIONS +.Pp +The function +.Fn memget +returns a pointer to a block of memory of at least the requested +.Fa size . +After adjusting +.Fa size +to the value +.Va new_size +as mentioned above in the +.Sx INTERNALS +subsection, the internal array of free lists is checked. +If there is no block of the needed +.Va new_size , +then +.Fn memget +will +.Xr malloc 3 +a chunk of memory which is as many times as +.Va new_size +will fit into the target size. This memory is then turned into a linked list +of +.Va new_size Ns No -sized +blocks which are given out as requested; the last such block is the first one +returned by +.Fn memget . +If the requested +.Fa size +is zero or negative, then +.Dv NULL +is returned and +.Va errno +is set to +.Dv EINVAL ; +if +.Fa size +is larger than or equal to the pre-defined maximum size +.Dv MEM_FREECOUNT , +then only a single block of exactly +.Fa size +will be +.Xr malloc 3 Ns No -d +and returned. +.Pp +The +.Fn memput +call is used to return memory once the caller is finished with it. +After adjusting +.Fa size +the the value +.Va new_size +as mentioned in the +.Sx INTERNALS +subsection, above, the block is placed at the head of the free list of +.Va new_size Ns -sized +blocks. +If the given +.Fa size +is zero or negative, then +.Va errno +is set to +.Dv EINVAL , +as for +.Fn memget . +If +.Fa size +is larger than or equal to the pre-defined maximum size +.Dv MEM_FREECOUNT , +then the block is immediately +.Xr free 3 Ns No -d . +.Pp +.Sy NOTE : +It is important that callers give +.Fn memput +.Em only +blocks of memory which were previously obtained from +.Fn memget +if the block is +.Em actually +less than +.Dv SMALL_SIZE_LIMIT +bytes in size. Since all blocks will be added to a free list, any block +which is not at least +.Dv SMALL_SIZE_LIMIT +bytes long will not be able to hold a pointer to the next block in the +free list. +.Pp +The +.Fn memstats +function will summarize the number of calls to +.Fn memget +and +.Fn memput +for any block size from 1 byte up to +.Pq Dv MEM_FREECOUNT No - 1 +bytes, followed by a single line for any calls using a +.Fa size +greater than or equal to +.Dv MEM_FREECOUNT ; +a brief header with shell-style comment lines prefaces the report and +explains the information. The +.Dv FILE +pointer +.Fa out +identifies the stream which is used for this report. Currently, +.Fn memstat +reports the number of calls to +.Fn memget +and +.Fn memput +using the caller-supplied value +.Fa size ; +the percentage of outstanding blocks of a given size (i.e., the percentage +by which calls to +.Fn memget +exceed +.Fn memput ) +are also reported on the line for blocks of the given +.Fa size . +However, the percent of blocks used is computed using the number of +blocks allocated according to the internal parameter +.Va new_size ; +it is the percentage of blocks used to those available at a given +.Va new_size , +and is computed using the +.Em total +number of caller +.Dq gets +for any caller +.Fa size Ns No -s +which map to the internally-computed +.Va new_size . +Keep in mind that +.Va new_size +is generally +.Em not +equal to +.Fa size , +which has these implications: +.Bl -enum -offset indent +.It +For +.Fa size +smaller than +.Dv SMALL_SIZE_LIMIT , +.Fn memstat +.Em will +show statistics for caller requests under +.Fa size , +but "percent used" information about such blocks will be reported under +.Dv SMALL_SIZE_LIMIT Ns No -sized +blocks. +.It +As a general case of point 1, internal statistics are reported on the the +line corresponding to +.Va new_size , +so that, for a given caller-supplied +.Fa size , +the associated internal information will appear on that line or on the next +line which shows "percent used" information. +.El +.Pp +.Sy NOTE : +If the caller returns blocks of a given +.Fa size +and requests others of +.Fa size Ns No -s +which map to the same internal +.Va new_size , +it is possible for +.Fn memstats +to report usage of greater than 100% for blocks of size +.Va new_size . +This should be viewed as A Good Thing. +.Sh RETURN VALUES +The function +.Fn memget +returns a +.No non- Ns Dv NULL +pointer to a block of memory of the requested +.Fa size . +It returns +.Dv NULL +if either the +.Fa size +is invalid (less than or equal to zero) or a +.Xr malloc 3 +of a new block of memory fails. In the former case, +.Va errno +is set to +.Dv EINVAL ; +in the latter, it is set to +.Dv ENOMEM . +.Pp +Neither +.Fn memput +nor +.Fn memstats +return a value. +.\" This next request is for sections 1, 6, 7 & 8 only +.\" .Sh ENVIRONMENT +.\" .Sh FILES +.\" .Sh EXAMPLES +.\" This next request is for sections 1, 6, 7 & 8 only +.\" (command return values (to shell) and +.\" fprintf/stderr type diagnostics) +.\" .Sh DIAGNOSTICS +.\" The next request is for sections 2 and 3 error +.\" and signal handling only. +.Sh ERRORS +.Va errno +is set as follows: +.Bl -tag -width "ENOMEM " -offset indent +.It Dv EINVAL +set by both +.Fn memget +and +.Fn memput +if the +.Fa size +is zero or negative +.It Dv ENOMEM +set by +.Fn memget +if a call to +.Xr malloc 3 +fails +.El +.Sh SEE ALSO +.Xr free 3 , +.Xr malloc 3 . +.\" .Sh STANDARDS +.\" .Sh HISTORY +.Sh AUTHORS +Steven J. Richardson and Paul Vixie, Vixie Enterprises. +.\" .Sh BUGS diff --git a/contrib/bind-9.5.2/lib/bind/isc/movefile.c b/contrib/bind-9.5.2/lib/bind/isc/movefile.c new file mode 100644 index 0000000000..191c46ed4a --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/movefile.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 2000 by Internet Software Consortium, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + + +#include +#include +#include +#include +#ifndef HAVE_MOVEFILE +/* + * rename() is lame (can't overwrite an existing file) on some systems. + * use movefile() instead, and let lame OS ports do what they need to. + */ + +int +isc_movefile(const char *oldname, const char *newname) { + return (rename(oldname, newname)); +} +#else + static int os_port_has_isc_movefile = 1; +#endif + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/isc/tree.c b/contrib/bind-9.5.2/lib/bind/isc/tree.c new file mode 100644 index 0000000000..8ba675fbe8 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/tree.c @@ -0,0 +1,534 @@ +#ifndef LINT +static const char rcsid[] = "$Id: tree.c,v 1.4 2005/04/27 04:56:39 sra Exp $"; +#endif + +/*% + * tree - balanced binary tree library + * + * vix 05apr94 [removed vixie.h dependencies; cleaned up formatting, names] + * vix 22jan93 [revisited; uses RCS, ANSI, POSIX; has bug fixes] + * vix 23jun86 [added delete uar to add for replaced nodes] + * vix 20jun86 [added tree_delete per wirth a+ds (mod2 v.) p. 224] + * vix 06feb86 [added tree_mung()] + * vix 02feb86 [added tree balancing from wirth "a+ds=p" p. 220-221] + * vix 14dec85 [written] + */ + +/*% + * This program text was created by Paul Vixie using examples from the book: + * "Algorithms & Data Structures," Niklaus Wirth, Prentice-Hall, 1986, ISBN + * 0-13-022005-1. Any errors in the conversion from Modula-2 to C are Paul + * Vixie's. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +/*#define DEBUG "tree"*/ + +#include "port_before.h" + +#include +#include + +#include "port_after.h" + +#include +#include + +#ifdef DEBUG +static int debugDepth = 0; +static char *debugFuncs[256]; +# define ENTER(proc) { \ + debugFuncs[debugDepth] = proc; \ + fprintf(stderr, "ENTER(%d:%s.%s)\n", \ + debugDepth, DEBUG, \ + debugFuncs[debugDepth]); \ + debugDepth++; \ + } +# define RET(value) { \ + debugDepth--; \ + fprintf(stderr, "RET(%d:%s.%s)\n", \ + debugDepth, DEBUG, \ + debugFuncs[debugDepth]); \ + return (value); \ + } +# define RETV { \ + debugDepth--; \ + fprintf(stderr, "RETV(%d:%s.%s)\n", \ + debugDepth, DEBUG, \ + debugFuncs[debugDepth]); \ + return; \ + } +# define MSG(msg) fprintf(stderr, "MSG(%s)\n", msg); +#else +# define ENTER(proc) ; +# define RET(value) return (value); +# define RETV return; +# define MSG(msg) ; +#endif + +#ifndef TRUE +# define TRUE 1 +# define FALSE 0 +#endif + +static tree * sprout(tree **, tree_t, int *, int (*)(), void (*)()); +static int delete(tree **, int (*)(), tree_t, void (*)(), int *, int *); +static void del(tree **, int *, tree **, void (*)(), int *); +static void bal_L(tree **, int *); +static void bal_R(tree **, int *); + +void +tree_init(tree **ppr_tree) { + ENTER("tree_init") + *ppr_tree = NULL; + RETV +} + +tree_t +tree_srch(tree **ppr_tree, int (*pfi_compare)(tree_t, tree_t), tree_t p_user) { + ENTER("tree_srch") + + if (*ppr_tree) { + int i_comp = (*pfi_compare)(p_user, (**ppr_tree).data); + + if (i_comp > 0) + RET(tree_srch(&(**ppr_tree).right, + pfi_compare, + p_user)) + + if (i_comp < 0) + RET(tree_srch(&(**ppr_tree).left, + pfi_compare, + p_user)) + + /* not higher, not lower... this must be the one. + */ + RET((**ppr_tree).data) + } + + /* grounded. NOT found. + */ + RET(NULL) +} + +tree_t +tree_add(tree **ppr_tree, int (*pfi_compare)(tree_t, tree_t), + tree_t p_user, void (*pfv_uar)()) +{ + int i_balance = FALSE; + + ENTER("tree_add") + if (!sprout(ppr_tree, p_user, &i_balance, pfi_compare, pfv_uar)) + RET(NULL) + RET(p_user) +} + +int +tree_delete(tree **ppr_p, int (*pfi_compare)(tree_t, tree_t), + tree_t p_user, void (*pfv_uar)()) +{ + int i_balance = FALSE, i_uar_called = FALSE; + + ENTER("tree_delete"); + RET(delete(ppr_p, pfi_compare, p_user, pfv_uar, + &i_balance, &i_uar_called)) +} + +int +tree_trav(tree **ppr_tree, int (*pfi_uar)(tree_t)) { + ENTER("tree_trav") + + if (!*ppr_tree) + RET(TRUE) + + if (!tree_trav(&(**ppr_tree).left, pfi_uar)) + RET(FALSE) + if (!(*pfi_uar)((**ppr_tree).data)) + RET(FALSE) + if (!tree_trav(&(**ppr_tree).right, pfi_uar)) + RET(FALSE) + RET(TRUE) +} + +void +tree_mung(tree **ppr_tree, void (*pfv_uar)(tree_t)) { + ENTER("tree_mung") + if (*ppr_tree) { + tree_mung(&(**ppr_tree).left, pfv_uar); + tree_mung(&(**ppr_tree).right, pfv_uar); + if (pfv_uar) + (*pfv_uar)((**ppr_tree).data); + memput(*ppr_tree, sizeof(tree)); + *ppr_tree = NULL; + } + RETV +} + +static tree * +sprout(tree **ppr, tree_t p_data, int *pi_balance, + int (*pfi_compare)(tree_t, tree_t), void (*pfv_delete)(tree_t)) +{ + tree *p1, *p2, *sub; + int cmp; + + ENTER("sprout") + + /* are we grounded? if so, add the node "here" and set the rebalance + * flag, then exit. + */ + if (!*ppr) { + MSG("grounded. adding new node, setting h=true") + *ppr = (tree *) memget(sizeof(tree)); + if (*ppr) { + (*ppr)->left = NULL; + (*ppr)->right = NULL; + (*ppr)->bal = 0; + (*ppr)->data = p_data; + *pi_balance = TRUE; + } + RET(*ppr); + } + + /* compare the data using routine passed by caller. + */ + cmp = (*pfi_compare)(p_data, (*ppr)->data); + + /* if LESS, prepare to move to the left. + */ + if (cmp < 0) { + MSG("LESS. sprouting left.") + sub = sprout(&(*ppr)->left, p_data, pi_balance, + pfi_compare, pfv_delete); + if (sub && *pi_balance) { /*%< left branch has grown */ + MSG("LESS: left branch has grown") + switch ((*ppr)->bal) { + case 1: + /* right branch WAS longer; bal is ok now */ + MSG("LESS: case 1.. bal restored implicitly") + (*ppr)->bal = 0; + *pi_balance = FALSE; + break; + case 0: + /* balance WAS okay; now left branch longer */ + MSG("LESS: case 0.. balnce bad but still ok") + (*ppr)->bal = -1; + break; + case -1: + /* left branch was already too long. rebal */ + MSG("LESS: case -1: rebalancing") + p1 = (*ppr)->left; + if (p1->bal == -1) { /*%< LL */ + MSG("LESS: single LL") + (*ppr)->left = p1->right; + p1->right = *ppr; + (*ppr)->bal = 0; + *ppr = p1; + } else { /*%< double LR */ + MSG("LESS: double LR") + + p2 = p1->right; + p1->right = p2->left; + p2->left = p1; + + (*ppr)->left = p2->right; + p2->right = *ppr; + + if (p2->bal == -1) + (*ppr)->bal = 1; + else + (*ppr)->bal = 0; + + if (p2->bal == 1) + p1->bal = -1; + else + p1->bal = 0; + *ppr = p2; + } /*else*/ + (*ppr)->bal = 0; + *pi_balance = FALSE; + } /*switch*/ + } /*if*/ + RET(sub) + } /*if*/ + + /* if MORE, prepare to move to the right. + */ + if (cmp > 0) { + MSG("MORE: sprouting to the right") + sub = sprout(&(*ppr)->right, p_data, pi_balance, + pfi_compare, pfv_delete); + if (sub && *pi_balance) { + MSG("MORE: right branch has grown") + + switch ((*ppr)->bal) { + case -1: + MSG("MORE: balance was off, fixed implicitly") + (*ppr)->bal = 0; + *pi_balance = FALSE; + break; + case 0: + MSG("MORE: balance was okay, now off but ok") + (*ppr)->bal = 1; + break; + case 1: + MSG("MORE: balance was off, need to rebalance") + p1 = (*ppr)->right; + if (p1->bal == 1) { /*%< RR */ + MSG("MORE: single RR") + (*ppr)->right = p1->left; + p1->left = *ppr; + (*ppr)->bal = 0; + *ppr = p1; + } else { /*%< double RL */ + MSG("MORE: double RL") + + p2 = p1->left; + p1->left = p2->right; + p2->right = p1; + + (*ppr)->right = p2->left; + p2->left = *ppr; + + if (p2->bal == 1) + (*ppr)->bal = -1; + else + (*ppr)->bal = 0; + + if (p2->bal == -1) + p1->bal = 1; + else + p1->bal = 0; + + *ppr = p2; + } /*else*/ + (*ppr)->bal = 0; + *pi_balance = FALSE; + } /*switch*/ + } /*if*/ + RET(sub) + } /*if*/ + + /* not less, not more: this is the same key! replace... + */ + MSG("FOUND: Replacing data value") + *pi_balance = FALSE; + if (pfv_delete) + (*pfv_delete)((*ppr)->data); + (*ppr)->data = p_data; + RET(*ppr) +} + +static int +delete(tree **ppr_p, int (*pfi_compare)(tree_t, tree_t), tree_t p_user, + void (*pfv_uar)(tree_t), int *pi_balance, int *pi_uar_called) +{ + tree *pr_q; + int i_comp, i_ret; + + ENTER("delete") + + if (*ppr_p == NULL) { + MSG("key not in tree") + RET(FALSE) + } + + i_comp = (*pfi_compare)((*ppr_p)->data, p_user); + if (i_comp > 0) { + MSG("too high - scan left") + i_ret = delete(&(*ppr_p)->left, pfi_compare, p_user, pfv_uar, + pi_balance, pi_uar_called); + if (*pi_balance) + bal_L(ppr_p, pi_balance); + } else if (i_comp < 0) { + MSG("too low - scan right") + i_ret = delete(&(*ppr_p)->right, pfi_compare, p_user, pfv_uar, + pi_balance, pi_uar_called); + if (*pi_balance) + bal_R(ppr_p, pi_balance); + } else { + MSG("equal") + pr_q = *ppr_p; + if (pr_q->right == NULL) { + MSG("right subtree null") + *ppr_p = pr_q->left; + *pi_balance = TRUE; + } else if (pr_q->left == NULL) { + MSG("right subtree non-null, left subtree null") + *ppr_p = pr_q->right; + *pi_balance = TRUE; + } else { + MSG("neither subtree null") + del(&pr_q->left, pi_balance, &pr_q, + pfv_uar, pi_uar_called); + if (*pi_balance) + bal_L(ppr_p, pi_balance); + } + if (!*pi_uar_called && pfv_uar) + (*pfv_uar)(pr_q->data); + /* Thanks to wuth@castrov.cuc.ab.ca for the following stmt. */ + memput(pr_q, sizeof(tree)); + i_ret = TRUE; + } + RET(i_ret) +} + +static void +del(tree **ppr_r, int *pi_balance, tree **ppr_q, + void (*pfv_uar)(tree_t), int *pi_uar_called) +{ + ENTER("del") + + if ((*ppr_r)->right != NULL) { + del(&(*ppr_r)->right, pi_balance, ppr_q, + pfv_uar, pi_uar_called); + if (*pi_balance) + bal_R(ppr_r, pi_balance); + } else { + if (pfv_uar) + (*pfv_uar)((*ppr_q)->data); + *pi_uar_called = TRUE; + (*ppr_q)->data = (*ppr_r)->data; + *ppr_q = *ppr_r; + *ppr_r = (*ppr_r)->left; + *pi_balance = TRUE; + } + + RETV +} + +static void +bal_L(tree **ppr_p, int *pi_balance) { + tree *p1, *p2; + int b1, b2; + + ENTER("bal_L") + MSG("left branch has shrunk") + + switch ((*ppr_p)->bal) { + case -1: + MSG("was imbalanced, fixed implicitly") + (*ppr_p)->bal = 0; + break; + case 0: + MSG("was okay, is now one off") + (*ppr_p)->bal = 1; + *pi_balance = FALSE; + break; + case 1: + MSG("was already off, this is too much") + p1 = (*ppr_p)->right; + b1 = p1->bal; + if (b1 >= 0) { + MSG("single RR") + (*ppr_p)->right = p1->left; + p1->left = *ppr_p; + if (b1 == 0) { + MSG("b1 == 0") + (*ppr_p)->bal = 1; + p1->bal = -1; + *pi_balance = FALSE; + } else { + MSG("b1 != 0") + (*ppr_p)->bal = 0; + p1->bal = 0; + } + *ppr_p = p1; + } else { + MSG("double RL") + p2 = p1->left; + b2 = p2->bal; + p1->left = p2->right; + p2->right = p1; + (*ppr_p)->right = p2->left; + p2->left = *ppr_p; + if (b2 == 1) + (*ppr_p)->bal = -1; + else + (*ppr_p)->bal = 0; + if (b2 == -1) + p1->bal = 1; + else + p1->bal = 0; + *ppr_p = p2; + p2->bal = 0; + } + } + RETV +} + +static void +bal_R(tree **ppr_p, int *pi_balance) { + tree *p1, *p2; + int b1, b2; + + ENTER("bal_R") + MSG("right branch has shrunk") + switch ((*ppr_p)->bal) { + case 1: + MSG("was imbalanced, fixed implicitly") + (*ppr_p)->bal = 0; + break; + case 0: + MSG("was okay, is now one off") + (*ppr_p)->bal = -1; + *pi_balance = FALSE; + break; + case -1: + MSG("was already off, this is too much") + p1 = (*ppr_p)->left; + b1 = p1->bal; + if (b1 <= 0) { + MSG("single LL") + (*ppr_p)->left = p1->right; + p1->right = *ppr_p; + if (b1 == 0) { + MSG("b1 == 0") + (*ppr_p)->bal = -1; + p1->bal = 1; + *pi_balance = FALSE; + } else { + MSG("b1 != 0") + (*ppr_p)->bal = 0; + p1->bal = 0; + } + *ppr_p = p1; + } else { + MSG("double LR") + p2 = p1->right; + b2 = p2->bal; + p1->right = p2->left; + p2->left = p1; + (*ppr_p)->left = p2->right; + p2->right = *ppr_p; + if (b2 == -1) + (*ppr_p)->bal = 1; + else + (*ppr_p)->bal = 0; + if (b2 == 1) + p1->bal = -1; + else + p1->bal = 0; + *ppr_p = p2; + p2->bal = 0; + } + } + RETV +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/isc/tree.mdoc b/contrib/bind-9.5.2/lib/bind/isc/tree.mdoc new file mode 100644 index 0000000000..2c24e1ff5c --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/isc/tree.mdoc @@ -0,0 +1,154 @@ +.\" $Id: tree.mdoc,v 1.3 2004/03/09 06:30:09 marka Exp $ +.\" +.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (c) 1995-1999 by Internet Software Consortium +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND 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. +.\" +.Dd April 5, 1994 +.Dt TREE 3 +.Os BSD 4 +.Sh NAME +.Nm tree_init , +.Nm tree_mung , +.Nm tree_srch , +.Nm tree_add , +.Nm tree_delete , +.Nm tree_trav +.Nd balanced binary tree routines +.Sh SYNOPSIS +.Ft void +.Fn tree_init "void **tree" +.Ft void * +.Fn tree_srch "void **tree" "int (*compare)()" "void *data" +.Ft void +.Fn tree_add "void **tree" "int (*compare)()" \ +"void *data" "void (*del_uar)()" +.Ft int +.Fn tree_delete "void **tree" "int (*compare)()" \ +"void *data" "void (*del_uar)()" +.Ft int +.Fn tree_trav "void **tree" "int (*trav_uar)()" +.Ft void +.Fn tree_mung "void **tree" "void (*del_uar)()" +.Sh DESCRIPTION +These functions create and manipulate a balanced binary (AVL) tree. Each node +of the tree contains the expected left & right subtree pointers, a short int +balance indicator, and a pointer to the user data. On a 32 bit system, this +means an overhead of 4+4+2+4 bytes per node (or, on a RISC or otherwise +alignment constrained system with implied padding, 4+4+4+4 bytes per node). +There is no key data type enforced by this package; a caller supplied +compare routine is used to compare user data blocks. +.Pp +Balanced binary trees are very fast on searches and replacements, but have a +moderately high cost for additions and deletions. If your application does a +lot more searches and replacements than it does additions and deletions, the +balanced (AVL) binary tree is a good choice for a data structure. +.Pp +.Fn Tree_init +creates an empty tree and binds it to +.Dq Fa tree +(which for this and all other routines in this package should be declared as +a pointer to void or int, and passed by reference), which can then be used by +other routines in this package. Note that more than one +.Dq Fa tree +variable can exist at once; thus multiple trees can be manipulated +simultaneously. +.Pp +.Fn Tree_srch +searches a tree for a specific node and returns either +.Fa NULL +if no node was found, or the value of the user data pointer if the node +was found. +.Fn compare +is the address of a function to compare two user data blocks. This routine +should work much the way +.Xr strcmp 3 +does; in fact, +.Xr strcmp +could be used if the user data was a \s-2NUL\s+2 terminated string. +.Dq Fa Data +is the address of a user data block to be used by +.Fn compare +as the search criteria. The tree is searched for a node where +.Fn compare +returns 0. +.Pp +.Fn Tree_add +inserts or replaces a node in the specified tree. The tree specified by +.Dq Fa tree +is searched as in +.Fn tree_srch , +and if a node is found to match +.Dq Fa data , +then the +.Fn del_uar +function, if non\-\s-2NULL\s+2, is called with the address of the user data +block for the node (this routine should deallocate any dynamic memory which +is referenced exclusively by the node); the user data pointer for the node +is then replaced by the value of +.Dq Fa data . +If no node is found to match, a new node is added (which may or may not +cause a transparent rebalance operation), with a user data pointer equal to +.Dq Fa data . +A rebalance may or may not occur, depending on where the node is added +and what the rest of the tree looks like. +.Fn Tree_add +will return the +.Dq Fa data +pointer unless catastrophe occurs in which case it will return \s-2NULL\s+2. +.Pp +.Fn Tree_delete +deletes a node from +.Dq Fa tree . +A rebalance may or may not occur, depending on where the node is removed from +and what the rest of the tree looks like. +.Fn Tree_delete +returns TRUE if a node was deleted, FALSE otherwise. +.Pp +.Fn Tree_trav +traverses all of +.Dq Fa tree , +calling +.Fn trav_uar +with the address of each user data block. If +.Fn trav_uar +returns FALSE at any time, +.Fn tree_trav +will immediately return FALSE to its caller. Otherwise all nodes will be +reached and +.Fn tree_trav +will return TRUE. +.Pp +.Fn Tree_mung +deletes every node in +.Dq Fa tree , +calling +.Fn del_uar +(if it is not \s-2NULL\s+2) with the user data address from each node (see +.Fn tree_add +and +.Fn tree_delete +above). The tree is left in the same state that +.Fn tree_init +leaves it in \- i.e., empty. +.Sh BUGS +Should have a way for the caller to specify application-specific +.Xr malloc +and +.Xr free +functions to be used internally when allocating meta data. +.Sh AUTHOR +Paul Vixie, converted and augumented from Modula\-2 examples in +.Dq Algorithms & Data Structures , +Niklaus Wirth, Prentice\-Hall, ISBN 0\-13\-022005\-1. diff --git a/contrib/bind-9.5.2/lib/bind/make/includes.in b/contrib/bind-9.5.2/lib/bind/make/includes.in new file mode 100644 index 0000000000..8f51b13a1c --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/make/includes.in @@ -0,0 +1,44 @@ +# Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2001 Internet Software Consortium. +# +# 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: includes.in,v 1.4 2007/06/19 23:47:13 tbox Exp $ + +# Search for machine-generated header files in the build tree, +# and for normal headers in the source tree (${top_srcdir}). +# We only need to look in OS-specific subdirectories for the +# latter case, because there are no machine-generated OS-specific +# headers. + +ISC_INCLUDES = @BIND9_ISC_BUILDINCLUDE@ \ + -I${top_srcdir}/lib/isc \ + -I${top_srcdir}/lib/isc/include \ + -I${top_srcdir}/lib/isc/unix/include \ + -I${top_srcdir}/lib/isc/@ISC_THREAD_DIR@/include + +ISCCFG_INCLUDES = @BIND9_ISCCFG_BUILDINCLUDE@ \ + -I${top_srcdir}/lib/isccfg/include + +DNS_INCLUDES = @BIND9_DNS_BUILDINCLUDE@ \ + -I${top_srcdir}/lib/dns/include \ + -I${top_srcdir}/lib/dns/sec/dst/include + +OMAPI_INCLUDES = @BIND9_OMAPI_BUILDINCLUDE@ \ + -I${top_srcdir}/lib/omapi/include + +LWRES_INCLUDES = @BIND9_LWRES_BUILDINCLUDE@ \ + -I${top_srcdir}/lib/lwres/include + +TEST_INCLUDES = \ + -I${top_srcdir}/lib/tests/include diff --git a/contrib/bind-9.5.2/lib/bind/make/mkdep.in b/contrib/bind-9.5.2/lib/bind/make/mkdep.in new file mode 100644 index 0000000000..60aea6fc6c --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/make/mkdep.in @@ -0,0 +1,147 @@ +#!/bin/sh - + +## ++Copyright++ 1987 +## - +## Copyright (c) 1987 Regents of the University of California. +## 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. All advertising materials mentioning features or use of this software +## must display the following acknowledgement: +## This product includes software developed by the University of +## California, Berkeley and its contributors. +## 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND +## ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +## ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +## FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +## DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +## OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +## HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +## LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +## OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +## SUCH DAMAGE. +## - +## Portions Copyright (c) 1993 by Digital Equipment Corporation. +## +## Permission to use, copy, modify, and distribute this software for any +## purpose with or without fee is hereby granted, provided that the above +## copyright notice and this permission notice appear in all copies, and that +## the name of Digital Equipment Corporation not be used in advertising or +## publicity pertaining to distribution of the document or software without +## specific, written prior permission. +## +## THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL +## WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES +## OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT +## CORPORATION 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. +## - +## --Copyright-- + +# +# @(#)mkdep.sh 5.12 (Berkeley) 6/30/88 +# + +MAKE=Makefile # default makefile name is "Makefile" + +while : + do case "$1" in + # -f allows you to select a makefile name + -f) + MAKE=$2 + shift; shift ;; + + # the -p flag produces "program: program.c" style dependencies + # so .o's don't get produced + -p) + SED='s;\.o;;' + shift ;; + *) + break ;; + esac +done + +if [ $# = 0 ] ; then + echo 'usage: mkdep [-p] [-f makefile] [flags] file ...' + exit 1 +fi + +if [ ! -w $MAKE ]; then + echo "mkdep: no writeable file \"$MAKE\"" + exit 1 +fi + +TMP=mkdep$$ + +trap 'rm -f $TMP ; exit 1' 1 2 3 13 15 + +cp $MAKE ${MAKE}.bak + +sed -e '/DO NOT DELETE THIS LINE/,$d' < $MAKE > $TMP + +cat << _EOF_ >> $TMP +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + +_EOF_ + +# If your compiler doesn't have -M, add it. If you can't, the next two +# lines will try and replace the "cc -M". The real problem is that this +# hack can't deal with anything that requires a search path, and doesn't +# even try for anything using bracket (<>) syntax. +# +# egrep '^#include[ ]*".*"' /dev/null $* | +# sed -e 's/:[^"]*"\([^"]*\)".*/: \1/' -e 's/\.c/.o/' | + +MKDEPPROG="@MKDEPPROG@" +if [ X"${MKDEPPROG}" != X ]; then + @SHELL@ -c "${MKDEPPROG} $*" +else + @MKDEPCC@ @MKDEPCFLAGS@ $* | + sed " + s; \./; ;g + $SED" | + awk '{ + if ($1 != prev) { + if (rec != "") + print rec; + rec = $0; + prev = $1; + } + else { + if (length(rec $2) > 78) { + print rec; + rec = $0; + } + else + rec = rec " " $2 + } + } + END { + print rec + }' >> $TMP +fi + +cat << _EOF_ >> $TMP + +# IF YOU PUT ANYTHING HERE IT WILL GO AWAY +_EOF_ + +# copy to preserve permissions +cp $TMP $MAKE +rm -f ${MAKE}.bak $TMP +exit 0 diff --git a/contrib/bind-9.5.2/lib/bind/make/rules.in b/contrib/bind-9.5.2/lib/bind/make/rules.in new file mode 100644 index 0000000000..f37998035f --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/make/rules.in @@ -0,0 +1,177 @@ +# Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2001, 2002 Internet Software Consortium. +# +# 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: rules.in,v 1.13 2007/06/18 23:47:34 tbox Exp $ + +### +### Common Makefile rules for BIND 9. +### + +### +### Paths +### +### Note: paths that vary by Makefile MUST NOT be listed +### here, or they won't get expanded correctly. + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +includedir = @includedir@ +libdir = @libdir@ +sysconfdir = @sysconfdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ + +DESTDIR = +MAKEDEFS= 'DESTDIR=${DESTDIR}' + +@SET_MAKE@ + +top_builddir = @BIND9_TOP_BUILDDIR@ +abs_top_srcdir = @abs_top_srcdir@ + +### +### All +### +### Makefile may define: +### TARGETS + +all: subdirs ${TARGETS} + +### +### Subdirectories +### +### Makefile may define: +### SUBDIRS + +ALL_SUBDIRS = ${SUBDIRS} nulldir + +# +# We use a single-colon rule so that additional dependencies of +# subdirectories can be specified after the inclusion of this file. +# The "depend" target is treated the same way. +# +subdirs: + @for i in ${ALL_SUBDIRS}; do \ + if [ "$$i" != "nulldir" -a -d $$i ]; then \ + echo "making all in `pwd`/$$i"; \ + (cd $$i; ${MAKE} ${MAKEDEFS} all) || exit 1; \ + fi; \ + done + +install clean distclean docclean manclean:: + @for i in ${ALL_SUBDIRS}; do \ + if [ "$$i" != "nulldir" -a -d $$i ]; then \ + echo "making $@ in `pwd`/$$i"; \ + (cd $$i; ${MAKE} ${MAKEDEFS} $@) || exit 1; \ + fi \ + done + +### +### C Programs +### +### Makefile must define +### CC +### Makefile may define +### CFLAGS +### CINCLUDES +### CDEFINES +### CWARNINGS +### User may define externally +### EXT_CFLAGS + +CC = @CC@ +CFLAGS = @CFLAGS@ +STD_CINCLUDES = @STD_CINCLUDES@ +STD_CDEFINES = @STD_CDEFINES@ +STD_CWARNINGS = @STD_CWARNINGS@ + +.SUFFIXES: +.SUFFIXES: .c .@O@ + +ALWAYS_INCLUDES = -I${top_builddir} -I${abs_top_srcdir}/@PORT_INCLUDE@ +ALWAYS_DEFINES = @ALWAYS_DEFINES@ +ALWAYS_WARNINGS = + +ALL_CPPFLAGS = \ + ${ALWAYS_INCLUDES} ${CINCLUDES} ${STD_CINCLUDES} \ + ${ALWAYS_DEFINES} ${CDEFINES} ${STD_CDEFINES} + +ALL_CFLAGS = ${EXT_CFLAGS} ${CFLAGS} \ + ${ALL_CPPFLAGS} \ + ${ALWAYS_WARNINGS} ${STD_CWARNINGS} ${CWARNINGS} + +.c.@O@: + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -c $< + +SHELL = @SHELL@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_MODE_COMPILE = ${LIBTOOL} @LIBTOOL_MODE_COMPILE@ +LIBTOOL_MODE_INSTALL = ${LIBTOOL} @LIBTOOL_MODE_INSTALL@ +LIBTOOL_MODE_LINK = ${LIBTOOL} @LIBTOOL_MODE_LINK@ +PURIFY = @PURIFY@ + +MKDEP = ${SHELL} ${top_builddir}/make/mkdep + +cleandir: distclean + +clean distclean:: + rm -f *.@O@ *.lo *.la core *.core .depend + rm -rf .libs + +distclean:: + rm -f Makefile + +depend: + @for i in ${ALL_SUBDIRS}; do \ + if [ "$$i" != "nulldir" -a -d $$i ]; then \ + echo "making depend in `pwd`/$$i"; \ + (cd $$i; ${MAKE} ${MAKEDEFS} $@) || exit 1; \ + fi \ + done + @if [ X"${SRCS}" != X -a X"${PSRCS}" != X ] ; then \ + echo ${MKDEP} ${ALL_CPPFLAGS} ${SRCS}; \ + ${MKDEP} ${ALL_CPPFLAGS} ${SRCS}; \ + echo ${MKDEP} -ap ${ALL_CPPFLAGS} ${PSRCS}; \ + ${MKDEP} -ap ${ALL_CPPFLAGS} ${PSRCS}; \ + ${DEPENDEXTRA} \ + elif [ X"${SRCS}" != X ] ; then \ + echo ${MKDEP} ${ALL_CPPFLAGS} ${SRCS}; \ + ${MKDEP} ${ALL_CPPFLAGS} ${SRCS}; \ + ${DEPENDEXTRA} \ + elif [ X"${PSRCS}" != X ] ; then \ + echo ${MKDEP} ${ALL_CPPFLAGS} ${PSRCS}; \ + ${MKDEP} -p ${ALL_CPPFLAGS} ${PSRCS}; \ + ${DEPENDEXTRA} \ + fi + +FORCE: + +### +### Libraries +### + +AR = @AR@ +ARFLAGS = @ARFLAGS@ +RANLIB = @RANLIB@ + +### +### Installation +### + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ diff --git a/contrib/bind-9.5.2/lib/bind/mkinstalldirs b/contrib/bind-9.5.2/lib/bind/mkinstalldirs new file mode 100755 index 0000000000..74a611ae83 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/mkinstalldirs @@ -0,0 +1,40 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Public domain + +# $Id: mkinstalldirs,v 1.1 2001/07/06 22:23:42 gson Exp $ + +errstatus=0 + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" 1>&2 + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/contrib/bind-9.5.2/lib/bind/nameser/ns_date.c b/contrib/bind-9.5.2/lib/bind/nameser/ns_date.c new file mode 100644 index 0000000000..292375af63 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/nameser/ns_date.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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 lint +static const char rcsid[] = "$Id: ns_date.c,v 1.6 2005/04/27 04:56:39 sra Exp $"; +#endif + +/* Import. */ + +#include "port_before.h" + +#include + +#include +#include +#include +#include +#include + +#include "port_after.h" + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +/* Forward. */ + +static int datepart(const char *, int, int, int, int *); + +/* Public. */ + +/*% + * Convert a date in ASCII into the number of seconds since + * 1 January 1970 (GMT assumed). Format is yyyymmddhhmmss, all + * digits required, no spaces allowed. + */ + +u_int32_t +ns_datetosecs(const char *cp, int *errp) { + struct tm time; + u_int32_t result; + int mdays, i; + static const int days_per_month[12] = + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + + if (strlen(cp) != 14U) { + *errp = 1; + return (0); + } + *errp = 0; + + memset(&time, 0, sizeof time); + time.tm_year = datepart(cp + 0, 4, 1990, 9999, errp) - 1900; + time.tm_mon = datepart(cp + 4, 2, 01, 12, errp) - 1; + time.tm_mday = datepart(cp + 6, 2, 01, 31, errp); + time.tm_hour = datepart(cp + 8, 2, 00, 23, errp); + time.tm_min = datepart(cp + 10, 2, 00, 59, errp); + time.tm_sec = datepart(cp + 12, 2, 00, 59, errp); + if (*errp) /*%< Any parse errors? */ + return (0); + + /* + * OK, now because timegm() is not available in all environments, + * we will do it by hand. Roll up sleeves, curse the gods, begin! + */ + +#define SECS_PER_DAY ((u_int32_t)24*60*60) +#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) + + result = time.tm_sec; /*%< Seconds */ + result += time.tm_min * 60; /*%< Minutes */ + result += time.tm_hour * (60*60); /*%< Hours */ + result += (time.tm_mday - 1) * SECS_PER_DAY; /*%< Days */ + /* Months are trickier. Look without leaping, then leap */ + mdays = 0; + for (i = 0; i < time.tm_mon; i++) + mdays += days_per_month[i]; + result += mdays * SECS_PER_DAY; /*%< Months */ + if (time.tm_mon > 1 && isleap(1900+time.tm_year)) + result += SECS_PER_DAY; /*%< Add leapday for this year */ + /* First figure years without leapdays, then add them in. */ + /* The loop is slow, FIXME, but simple and accurate. */ + result += (time.tm_year - 70) * (SECS_PER_DAY*365); /*%< Years */ + for (i = 70; i < time.tm_year; i++) + if (isleap(1900+i)) + result += SECS_PER_DAY; /*%< Add leapday for prev year */ + return (result); +} + +/* Private. */ + +/*% + * Parse part of a date. Set error flag if any error. + * Don't reset the flag if there is no error. + */ +static int +datepart(const char *buf, int size, int min, int max, int *errp) { + int result = 0; + int i; + + for (i = 0; i < size; i++) { + if (!isdigit((unsigned char)(buf[i]))) + *errp = 1; + result = (result * 10) + buf[i] - '0'; + } + if (result < min) + *errp = 1; + if (result > max) + *errp = 1; + return (result); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/nameser/ns_name.c b/contrib/bind-9.5.2/lib/bind/nameser/ns_name.c new file mode 100644 index 0000000000..9d409f3d95 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/nameser/ns_name.c @@ -0,0 +1,973 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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 lint +static const char rcsid[] = "$Id: ns_name.c,v 1.10 2005/04/27 04:56:40 sra Exp $"; +#endif + +#include "port_before.h" + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "port_after.h" + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +#define NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */ +#define DNS_LABELTYPE_BITSTRING 0x41 + +/* Data. */ + +static const char digits[] = "0123456789"; + +static const char digitvalue[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/ +}; + +/* Forward. */ + +static int special(int); +static int printable(int); +static int dn_find(const u_char *, const u_char *, + const u_char * const *, + const u_char * const *); +static int encode_bitsring(const char **, const char *, + unsigned char **, unsigned char **, + unsigned const char *); +static int labellen(const u_char *); +static int decode_bitstring(const unsigned char **, + char *, const char *); + +/* Public. */ + +/*% + * Convert an encoded domain name to printable ascii as per RFC1035. + + * return: + *\li Number of bytes written to buffer, or -1 (with errno set) + * + * notes: + *\li The root is returned as "." + *\li All other domains are returned in non absolute form + */ +int +ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) +{ + const u_char *cp; + char *dn, *eom; + u_char c; + u_int n; + int l; + + cp = src; + dn = dst; + eom = dst + dstsiz; + + while ((n = *cp++) != 0) { + if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + /* Some kind of compression pointer. */ + errno = EMSGSIZE; + return (-1); + } + if (dn != dst) { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '.'; + } + if ((l = labellen(cp - 1)) < 0) { + errno = EMSGSIZE; /*%< XXX */ + return(-1); + } + if (dn + l >= eom) { + errno = EMSGSIZE; + return (-1); + } + if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) { + int m; + + if (n != DNS_LABELTYPE_BITSTRING) { + /* XXX: labellen should reject this case */ + errno = EINVAL; + return(-1); + } + if ((m = decode_bitstring(&cp, dn, eom)) < 0) + { + errno = EMSGSIZE; + return(-1); + } + dn += m; + continue; + } + for ((void)NULL; l > 0; l--) { + c = *cp++; + if (special(c)) { + if (dn + 1 >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\\'; + *dn++ = (char)c; + } else if (!printable(c)) { + if (dn + 3 >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\\'; + *dn++ = digits[c / 100]; + *dn++ = digits[(c % 100) / 10]; + *dn++ = digits[c % 10]; + } else { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = (char)c; + } + } + } + if (dn == dst) { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '.'; + } + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\0'; + return (dn - dst); +} + +/*% + * Convert a ascii string into an encoded domain name as per RFC1035. + * + * return: + * + *\li -1 if it fails + *\li 1 if string was fully qualified + *\li 0 is string was not fully qualified + * + * notes: + *\li Enforces label and domain length limits. + */ + +int +ns_name_pton(const char *src, u_char *dst, size_t dstsiz) +{ + u_char *label, *bp, *eom; + int c, n, escaped, e = 0; + char *cp; + + escaped = 0; + bp = dst; + eom = dst + dstsiz; + label = bp++; + + while ((c = *src++) != 0) { + if (escaped) { + if (c == '[') { /*%< start a bit string label */ + if ((cp = strchr(src, ']')) == NULL) { + errno = EINVAL; /*%< ??? */ + return(-1); + } + if ((e = encode_bitsring(&src, cp + 2, + &label, &bp, eom)) + != 0) { + errno = e; + return(-1); + } + escaped = 0; + label = bp++; + if ((c = *src++) == 0) + goto done; + else if (c != '.') { + errno = EINVAL; + return(-1); + } + continue; + } + else if ((cp = strchr(digits, c)) != NULL) { + n = (cp - digits) * 100; + if ((c = *src++) == 0 || + (cp = strchr(digits, c)) == NULL) { + errno = EMSGSIZE; + return (-1); + } + n += (cp - digits) * 10; + if ((c = *src++) == 0 || + (cp = strchr(digits, c)) == NULL) { + errno = EMSGSIZE; + return (-1); + } + n += (cp - digits); + if (n > 255) { + errno = EMSGSIZE; + return (-1); + } + c = n; + } + escaped = 0; + } else if (c == '\\') { + escaped = 1; + continue; + } else if (c == '.') { + c = (bp - label - 1); + if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */ + errno = EMSGSIZE; + return (-1); + } + if (label >= eom) { + errno = EMSGSIZE; + return (-1); + } + *label = c; + /* Fully qualified ? */ + if (*src == '\0') { + if (c != 0) { + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = '\0'; + } + if ((bp - dst) > MAXCDNAME) { + errno = EMSGSIZE; + return (-1); + } + return (1); + } + if (c == 0 || *src == '.') { + errno = EMSGSIZE; + return (-1); + } + label = bp++; + continue; + } + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = (u_char)c; + } + c = (bp - label - 1); + if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */ + errno = EMSGSIZE; + return (-1); + } + done: + if (label >= eom) { + errno = EMSGSIZE; + return (-1); + } + *label = c; + if (c != 0) { + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = 0; + } + if ((bp - dst) > MAXCDNAME) { /*%< src too big */ + errno = EMSGSIZE; + return (-1); + } + return (0); +} + +/*% + * Convert a network strings labels into all lowercase. + * + * return: + *\li Number of bytes written to buffer, or -1 (with errno set) + * + * notes: + *\li Enforces label and domain length limits. + */ + +int +ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz) +{ + const u_char *cp; + u_char *dn, *eom; + u_char c; + u_int n; + int l; + + cp = src; + dn = dst; + eom = dst + dstsiz; + + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + while ((n = *cp++) != 0) { + if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + /* Some kind of compression pointer. */ + errno = EMSGSIZE; + return (-1); + } + *dn++ = n; + if ((l = labellen(cp - 1)) < 0) { + errno = EMSGSIZE; + return (-1); + } + if (dn + l >= eom) { + errno = EMSGSIZE; + return (-1); + } + for ((void)NULL; l > 0; l--) { + c = *cp++; + if (isupper(c)) + *dn++ = tolower(c); + else + *dn++ = c; + } + } + *dn++ = '\0'; + return (dn - dst); +} + +/*% + * Unpack a domain name from a message, source may be compressed. + * + * return: + *\li -1 if it fails, or consumed octets if it succeeds. + */ +int +ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src, + u_char *dst, size_t dstsiz) +{ + const u_char *srcp, *dstlim; + u_char *dstp; + int n, len, checked, l; + + len = -1; + checked = 0; + dstp = dst; + srcp = src; + dstlim = dst + dstsiz; + if (srcp < msg || srcp >= eom) { + errno = EMSGSIZE; + return (-1); + } + /* Fetch next label in domain name. */ + while ((n = *srcp++) != 0) { + /* Check for indirection. */ + switch (n & NS_CMPRSFLGS) { + case 0: + case NS_TYPE_ELT: + /* Limit checks. */ + if ((l = labellen(srcp - 1)) < 0) { + errno = EMSGSIZE; + return(-1); + } + if (dstp + l + 1 >= dstlim || srcp + l >= eom) { + errno = EMSGSIZE; + return (-1); + } + checked += l + 1; + *dstp++ = n; + memcpy(dstp, srcp, l); + dstp += l; + srcp += l; + break; + + case NS_CMPRSFLGS: + if (srcp >= eom) { + errno = EMSGSIZE; + return (-1); + } + if (len < 0) + len = srcp - src + 1; + srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff)); + if (srcp < msg || srcp >= eom) { /*%< Out of range. */ + errno = EMSGSIZE; + return (-1); + } + checked += 2; + /* + * Check for loops in the compressed name; + * if we've looked at the whole message, + * there must be a loop. + */ + if (checked >= eom - msg) { + errno = EMSGSIZE; + return (-1); + } + break; + + default: + errno = EMSGSIZE; + return (-1); /*%< flag error */ + } + } + *dstp = '\0'; + if (len < 0) + len = srcp - src; + return (len); +} + +/*% + * Pack domain name 'domain' into 'comp_dn'. + * + * return: + *\li Size of the compressed name, or -1. + * + * notes: + *\li 'dnptrs' is an array of pointers to previous compressed names. + *\li dnptrs[0] is a pointer to the beginning of the message. The array + * ends with NULL. + *\li 'lastdnptr' is a pointer to the end of the array pointed to + * by 'dnptrs'. + * + * Side effects: + *\li The list of pointers in dnptrs is updated for labels inserted into + * the message as we compress the name. If 'dnptr' is NULL, we don't + * try to compress names. If 'lastdnptr' is NULL, we don't update the + * list. + */ +int +ns_name_pack(const u_char *src, u_char *dst, int dstsiz, + const u_char **dnptrs, const u_char **lastdnptr) +{ + u_char *dstp; + const u_char **cpp, **lpp, *eob, *msg; + const u_char *srcp; + int n, l, first = 1; + + srcp = src; + dstp = dst; + eob = dstp + dstsiz; + lpp = cpp = NULL; + if (dnptrs != NULL) { + if ((msg = *dnptrs++) != NULL) { + for (cpp = dnptrs; *cpp != NULL; cpp++) + (void)NULL; + lpp = cpp; /*%< end of list to search */ + } + } else + msg = NULL; + + /* make sure the domain we are about to add is legal */ + l = 0; + do { + int l0; + + n = *srcp; + if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + errno = EMSGSIZE; + return (-1); + } + if ((l0 = labellen(srcp)) < 0) { + errno = EINVAL; + return(-1); + } + l += l0 + 1; + if (l > MAXCDNAME) { + errno = EMSGSIZE; + return (-1); + } + srcp += l0 + 1; + } while (n != 0); + + /* from here on we need to reset compression pointer array on error */ + srcp = src; + do { + /* Look to see if we can use pointers. */ + n = *srcp; + if (n != 0 && msg != NULL) { + l = dn_find(srcp, msg, (const u_char * const *)dnptrs, + (const u_char * const *)lpp); + if (l >= 0) { + if (dstp + 1 >= eob) { + goto cleanup; + } + *dstp++ = (l >> 8) | NS_CMPRSFLGS; + *dstp++ = l % 256; + return (dstp - dst); + } + /* Not found, save it. */ + if (lastdnptr != NULL && cpp < lastdnptr - 1 && + (dstp - msg) < 0x4000 && first) { + *cpp++ = dstp; + *cpp = NULL; + first = 0; + } + } + /* copy label to buffer */ + if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + /* Should not happen. */ + goto cleanup; + } + n = labellen(srcp); + if (dstp + 1 + n >= eob) { + goto cleanup; + } + memcpy(dstp, srcp, n + 1); + srcp += n + 1; + dstp += n + 1; + } while (n != 0); + + if (dstp > eob) { +cleanup: + if (msg != NULL) + *lpp = NULL; + errno = EMSGSIZE; + return (-1); + } + return (dstp - dst); +} + +/*% + * Expand compressed domain name to presentation format. + * + * return: + *\li Number of bytes read out of `src', or -1 (with errno set). + * + * note: + *\li Root domain returns as "." not "". + */ +int +ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src, + char *dst, size_t dstsiz) +{ + u_char tmp[NS_MAXCDNAME]; + int n; + + if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1) + return (-1); + if (ns_name_ntop(tmp, dst, dstsiz) == -1) + return (-1); + return (n); +} + +/*% + * Compress a domain name into wire format, using compression pointers. + * + * return: + *\li Number of bytes consumed in `dst' or -1 (with errno set). + * + * notes: + *\li 'dnptrs' is an array of pointers to previous compressed names. + *\li dnptrs[0] is a pointer to the beginning of the message. + *\li The list ends with NULL. 'lastdnptr' is a pointer to the end of the + * array pointed to by 'dnptrs'. Side effect is to update the list of + * pointers for labels inserted into the message as we compress the name. + *\li If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' + * is NULL, we don't update the list. + */ +int +ns_name_compress(const char *src, u_char *dst, size_t dstsiz, + const u_char **dnptrs, const u_char **lastdnptr) +{ + u_char tmp[NS_MAXCDNAME]; + + if (ns_name_pton(src, tmp, sizeof tmp) == -1) + return (-1); + return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr)); +} + +/*% + * Reset dnptrs so that there are no active references to pointers at or + * after src. + */ +void +ns_name_rollback(const u_char *src, const u_char **dnptrs, + const u_char **lastdnptr) +{ + while (dnptrs < lastdnptr && *dnptrs != NULL) { + if (*dnptrs >= src) { + *dnptrs = NULL; + break; + } + dnptrs++; + } +} + +/*% + * Advance *ptrptr to skip over the compressed name it points at. + * + * return: + *\li 0 on success, -1 (with errno set) on failure. + */ +int +ns_name_skip(const u_char **ptrptr, const u_char *eom) +{ + const u_char *cp; + u_int n; + int l; + + cp = *ptrptr; + while (cp < eom && (n = *cp++) != 0) { + /* Check for indirection. */ + switch (n & NS_CMPRSFLGS) { + case 0: /*%< normal case, n == len */ + cp += n; + continue; + case NS_TYPE_ELT: /*%< EDNS0 extended label */ + if ((l = labellen(cp - 1)) < 0) { + errno = EMSGSIZE; /*%< XXX */ + return(-1); + } + cp += l; + continue; + case NS_CMPRSFLGS: /*%< indirection */ + cp++; + break; + default: /*%< illegal type */ + errno = EMSGSIZE; + return (-1); + } + break; + } + if (cp > eom) { + errno = EMSGSIZE; + return (-1); + } + *ptrptr = cp; + return (0); +} + +/* Private. */ + +/*% + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this characted special ("in need of quoting") ? + * + * return: + *\li boolean. + */ +static int +special(int ch) { + switch (ch) { + case 0x22: /*%< '"' */ + case 0x2E: /*%< '.' */ + case 0x3B: /*%< ';' */ + case 0x5C: /*%< '\\' */ + case 0x28: /*%< '(' */ + case 0x29: /*%< ')' */ + /* Special modifiers in zone files. */ + case 0x40: /*%< '@' */ + case 0x24: /*%< '$' */ + return (1); + default: + return (0); + } +} + +/*% + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this character visible and not a space when printed ? + * + * return: + *\li boolean. + */ +static int +printable(int ch) { + return (ch > 0x20 && ch < 0x7f); +} + +/*% + * Thinking in noninternationalized USASCII (per the DNS spec), + * convert this character to lower case if it's upper case. + */ +static int +mklower(int ch) { + if (ch >= 0x41 && ch <= 0x5A) + return (ch + 0x20); + return (ch); +} + +/*% + * Search for the counted-label name in an array of compressed names. + * + * return: + *\li offset from msg if found, or -1. + * + * notes: + *\li dnptrs is the pointer to the first name on the list, + *\li not the pointer to the start of the message. + */ +static int +dn_find(const u_char *domain, const u_char *msg, + const u_char * const *dnptrs, + const u_char * const *lastdnptr) +{ + const u_char *dn, *cp, *sp; + const u_char * const *cpp; + u_int n; + + for (cpp = dnptrs; cpp < lastdnptr; cpp++) { + sp = *cpp; + /* + * terminate search on: + * root label + * compression pointer + * unusable offset + */ + while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 && + (sp - msg) < 0x4000) { + dn = domain; + cp = sp; + while ((n = *cp++) != 0) { + /* + * check for indirection + */ + switch (n & NS_CMPRSFLGS) { + case 0: /*%< normal case, n == len */ + n = labellen(cp - 1); /*%< XXX */ + if (n != *dn++) + goto next; + + for ((void)NULL; n > 0; n--) + if (mklower(*dn++) != + mklower(*cp++)) + goto next; + /* Is next root for both ? */ + if (*dn == '\0' && *cp == '\0') + return (sp - msg); + if (*dn) + continue; + goto next; + case NS_CMPRSFLGS: /*%< indirection */ + cp = msg + (((n & 0x3f) << 8) | *cp); + break; + + default: /*%< illegal type */ + errno = EMSGSIZE; + return (-1); + } + } + next: ; + sp += *sp + 1; + } + } + errno = ENOENT; + return (-1); +} + +static int +decode_bitstring(const unsigned char **cpp, char *dn, const char *eom) +{ + const unsigned char *cp = *cpp; + char *beg = dn, tc; + int b, blen, plen, i; + + if ((blen = (*cp & 0xff)) == 0) + blen = 256; + plen = (blen + 3) / 4; + plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1); + if (dn + plen >= eom) + return(-1); + + cp++; + i = SPRINTF((dn, "\\[x")); + if (i < 0) + return (-1); + dn += i; + for (b = blen; b > 7; b -= 8, cp++) { + i = SPRINTF((dn, "%02x", *cp & 0xff)); + if (i < 0) + return (-1); + dn += i; + } + if (b > 4) { + tc = *cp++; + i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b)))); + if (i < 0) + return (-1); + dn += i; + } else if (b > 0) { + tc = *cp++; + i = SPRINTF((dn, "%1x", + ((tc >> 4) & 0x0f) & (0x0f << (4 - b)))); + if (i < 0) + return (-1); + dn += i; + } + i = SPRINTF((dn, "/%d]", blen)); + if (i < 0) + return (-1); + dn += i; + + *cpp = cp; + return(dn - beg); +} + +static int +encode_bitsring(const char **bp, const char *end, unsigned char **labelp, + unsigned char ** dst, unsigned const char *eom) +{ + int afterslash = 0; + const char *cp = *bp; + unsigned char *tp; + char c; + const char *beg_blen; + char *end_blen = NULL; + int value = 0, count = 0, tbcount = 0, blen = 0; + + beg_blen = end_blen = NULL; + + /* a bitstring must contain at least 2 characters */ + if (end - cp < 2) + return(EINVAL); + + /* XXX: currently, only hex strings are supported */ + if (*cp++ != 'x') + return(EINVAL); + if (!isxdigit((*cp) & 0xff)) /*%< reject '\[x/BLEN]' */ + return(EINVAL); + + for (tp = *dst + 1; cp < end && tp < eom; cp++) { + switch((c = *cp)) { + case ']': /*%< end of the bitstring */ + if (afterslash) { + if (beg_blen == NULL) + return(EINVAL); + blen = (int)strtol(beg_blen, &end_blen, 10); + if (*end_blen != ']') + return(EINVAL); + } + if (count) + *tp++ = ((value << 4) & 0xff); + cp++; /*%< skip ']' */ + goto done; + case '/': + afterslash = 1; + break; + default: + if (afterslash) { + if (!isdigit(c&0xff)) + return(EINVAL); + if (beg_blen == NULL) { + + if (c == '0') { + /* blen never begings with 0 */ + return(EINVAL); + } + beg_blen = cp; + } + } else { + if (!isxdigit(c&0xff)) + return(EINVAL); + value <<= 4; + value += digitvalue[(int)c]; + count += 4; + tbcount += 4; + if (tbcount > 256) + return(EINVAL); + if (count == 8) { + *tp++ = value; + count = 0; + } + } + break; + } + } + done: + if (cp >= end || tp >= eom) + return(EMSGSIZE); + + /* + * bit length validation: + * If a is present, the number of digits in the + * MUST be just sufficient to contain the number of bits specified + * by the . If there are insignificant bits in a final + * hexadecimal or octal digit, they MUST be zero. + * RFC2673, Section 3.2. + */ + if (blen > 0) { + int traillen; + + if (((blen + 3) & ~3) != tbcount) + return(EINVAL); + traillen = tbcount - blen; /*%< between 0 and 3 */ + if (((value << (8 - traillen)) & 0xff) != 0) + return(EINVAL); + } + else + blen = tbcount; + if (blen == 256) + blen = 0; + + /* encode the type and the significant bit fields */ + **labelp = DNS_LABELTYPE_BITSTRING; + **dst = blen; + + *bp = cp; + *dst = tp; + + return(0); +} + +static int +labellen(const u_char *lp) +{ + int bitlen; + u_char l = *lp; + + if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + /* should be avoided by the caller */ + return(-1); + } + + if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) { + if (l == DNS_LABELTYPE_BITSTRING) { + if ((bitlen = *(lp + 1)) == 0) + bitlen = 256; + return((bitlen + 7 ) / 8 + 1); + } + return(-1); /*%< unknwon ELT */ + } + return(l); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/nameser/ns_netint.c b/contrib/bind-9.5.2/lib/bind/nameser/ns_netint.c new file mode 100644 index 0000000000..559c9d5bd5 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/nameser/ns_netint.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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 lint +static const char rcsid[] = "$Id: ns_netint.c,v 1.3 2005/04/27 04:56:40 sra Exp $"; +#endif + +/* Import. */ + +#include "port_before.h" + +#include + +#include "port_after.h" + +/* Public. */ + +u_int +ns_get16(const u_char *src) { + u_int dst; + + NS_GET16(dst, src); + return (dst); +} + +u_long +ns_get32(const u_char *src) { + u_long dst; + + NS_GET32(dst, src); + return (dst); +} + +void +ns_put16(u_int src, u_char *dst) { + NS_PUT16(src, dst); +} + +void +ns_put32(u_long src, u_char *dst) { + NS_PUT32(src, dst); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/nameser/ns_parse.c b/contrib/bind-9.5.2/lib/bind/nameser/ns_parse.c new file mode 100644 index 0000000000..09b19f861c --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/nameser/ns_parse.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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 lint +static const char rcsid[] = "$Id: ns_parse.c,v 1.9 2007/08/27 03:32:26 marka Exp $"; +#endif + +/* Import. */ + +#include "port_before.h" + +#include + +#include +#include + +#include +#include +#include + +#include "port_after.h" + +/* Forward. */ + +static void setsection(ns_msg *msg, ns_sect sect); + +/* Macros. */ + +#if !defined(SOLARIS2) || defined(__COVERITY__) +#define RETERR(err) do { errno = (err); return (-1); } while (0) +#else +#define RETERR(err) \ + do { errno = (err); if (errno == errno) return (-1); } while (0) +#endif + +/* Public. */ + +/* These need to be in the same order as the nres.h:ns_flag enum. */ +struct _ns_flagdata _ns_flagdata[16] = { + { 0x8000, 15 }, /*%< qr. */ + { 0x7800, 11 }, /*%< opcode. */ + { 0x0400, 10 }, /*%< aa. */ + { 0x0200, 9 }, /*%< tc. */ + { 0x0100, 8 }, /*%< rd. */ + { 0x0080, 7 }, /*%< ra. */ + { 0x0040, 6 }, /*%< z. */ + { 0x0020, 5 }, /*%< ad. */ + { 0x0010, 4 }, /*%< cd. */ + { 0x000f, 0 }, /*%< rcode. */ + { 0x0000, 0 }, /*%< expansion (1/6). */ + { 0x0000, 0 }, /*%< expansion (2/6). */ + { 0x0000, 0 }, /*%< expansion (3/6). */ + { 0x0000, 0 }, /*%< expansion (4/6). */ + { 0x0000, 0 }, /*%< expansion (5/6). */ + { 0x0000, 0 }, /*%< expansion (6/6). */ +}; + +int ns_msg_getflag(ns_msg handle, int flag) { + return(((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift); +} + +int +ns_skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) { + const u_char *optr = ptr; + + for ((void)NULL; count > 0; count--) { + int b, rdlength; + + b = dn_skipname(ptr, eom); + if (b < 0) + RETERR(EMSGSIZE); + ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/; + if (section != ns_s_qd) { + if (ptr + NS_INT32SZ + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + ptr += NS_INT32SZ/*TTL*/; + NS_GET16(rdlength, ptr); + ptr += rdlength/*RData*/; + } + } + if (ptr > eom) + RETERR(EMSGSIZE); + return (ptr - optr); +} + +int +ns_initparse(const u_char *msg, int msglen, ns_msg *handle) { + const u_char *eom = msg + msglen; + int i; + + memset(handle, 0x5e, sizeof *handle); + handle->_msg = msg; + handle->_eom = eom; + if (msg + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + NS_GET16(handle->_id, msg); + if (msg + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + NS_GET16(handle->_flags, msg); + for (i = 0; i < ns_s_max; i++) { + if (msg + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + NS_GET16(handle->_counts[i], msg); + } + for (i = 0; i < ns_s_max; i++) + if (handle->_counts[i] == 0) + handle->_sections[i] = NULL; + else { + int b = ns_skiprr(msg, eom, (ns_sect)i, + handle->_counts[i]); + + if (b < 0) + return (-1); + handle->_sections[i] = msg; + msg += b; + } + if (msg != eom) + RETERR(EMSGSIZE); + setsection(handle, ns_s_max); + return (0); +} + +int +ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) { + int b; + int tmp; + + /* Make section right. */ + tmp = section; + if (tmp < 0 || section >= ns_s_max) + RETERR(ENODEV); + if (section != handle->_sect) + setsection(handle, section); + + /* Make rrnum right. */ + if (rrnum == -1) + rrnum = handle->_rrnum; + if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) + RETERR(ENODEV); + if (rrnum < handle->_rrnum) + setsection(handle, section); + if (rrnum > handle->_rrnum) { + b = ns_skiprr(handle->_msg_ptr, handle->_eom, section, + rrnum - handle->_rrnum); + + if (b < 0) + return (-1); + handle->_msg_ptr += b; + handle->_rrnum = rrnum; + } + + /* Do the parse. */ + b = dn_expand(handle->_msg, handle->_eom, + handle->_msg_ptr, rr->name, NS_MAXDNAME); + if (b < 0) + return (-1); + handle->_msg_ptr += b; + if (handle->_msg_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom) + RETERR(EMSGSIZE); + NS_GET16(rr->type, handle->_msg_ptr); + NS_GET16(rr->rr_class, handle->_msg_ptr); + if (section == ns_s_qd) { + rr->ttl = 0; + rr->rdlength = 0; + rr->rdata = NULL; + } else { + if (handle->_msg_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom) + RETERR(EMSGSIZE); + NS_GET32(rr->ttl, handle->_msg_ptr); + NS_GET16(rr->rdlength, handle->_msg_ptr); + if (handle->_msg_ptr + rr->rdlength > handle->_eom) + RETERR(EMSGSIZE); + rr->rdata = handle->_msg_ptr; + handle->_msg_ptr += rr->rdlength; + } + if (++handle->_rrnum > handle->_counts[(int)section]) + setsection(handle, (ns_sect)((int)section + 1)); + + /* All done. */ + return (0); +} + +/* Private. */ + +static void +setsection(ns_msg *msg, ns_sect sect) { + msg->_sect = sect; + if (sect == ns_s_max) { + msg->_rrnum = -1; + msg->_msg_ptr = NULL; + } else { + msg->_rrnum = 0; + msg->_msg_ptr = msg->_sections[(int)sect]; + } +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/nameser/ns_print.c b/contrib/bind-9.5.2/lib/bind/nameser/ns_print.c new file mode 100644 index 0000000000..6a23e9add6 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/nameser/ns_print.c @@ -0,0 +1,897 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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 lint +static const char rcsid[] = "$Id: ns_print.c,v 1.10 2005/04/27 04:56:40 sra Exp $"; +#endif + +/* Import. */ + +#include "port_before.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "port_after.h" + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +/* Forward. */ + +static size_t prune_origin(const char *name, const char *origin); +static int charstr(const u_char *rdata, const u_char *edata, + char **buf, size_t *buflen); +static int addname(const u_char *msg, size_t msglen, + const u_char **p, const char *origin, + char **buf, size_t *buflen); +static void addlen(size_t len, char **buf, size_t *buflen); +static int addstr(const char *src, size_t len, + char **buf, size_t *buflen); +static int addtab(size_t len, size_t target, int spaced, + char **buf, size_t *buflen); + +/* Macros. */ + +#define T(x) \ + do { \ + if ((x) < 0) \ + return (-1); \ + } while (0) + +/* Public. */ + +/*% + * Convert an RR to presentation format. + * + * return: + *\li Number of characters written to buf, or -1 (check errno). + */ +int +ns_sprintrr(const ns_msg *handle, const ns_rr *rr, + const char *name_ctx, const char *origin, + char *buf, size_t buflen) +{ + int n; + + n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle), + ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr), + ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr), + name_ctx, origin, buf, buflen); + return (n); +} + +/*% + * Convert the fields of an RR into presentation format. + * + * return: + *\li Number of characters written to buf, or -1 (check errno). + */ +int +ns_sprintrrf(const u_char *msg, size_t msglen, + const char *name, ns_class class, ns_type type, + u_long ttl, const u_char *rdata, size_t rdlen, + const char *name_ctx, const char *origin, + char *buf, size_t buflen) +{ + const char *obuf = buf; + const u_char *edata = rdata + rdlen; + int spaced = 0; + + const char *comment; + char tmp[100]; + int len, x; + + /* + * Owner. + */ + if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) { + T(addstr("\t\t\t", 3, &buf, &buflen)); + } else { + len = prune_origin(name, origin); + if (*name == '\0') { + goto root; + } else if (len == 0) { + T(addstr("@\t\t\t", 4, &buf, &buflen)); + } else { + T(addstr(name, len, &buf, &buflen)); + /* Origin not used or not root, and no trailing dot? */ + if (((origin == NULL || origin[0] == '\0') || + (origin[0] != '.' && origin[1] != '\0' && + name[len] == '\0')) && name[len - 1] != '.') { + root: + T(addstr(".", 1, &buf, &buflen)); + len++; + } + T(spaced = addtab(len, 24, spaced, &buf, &buflen)); + } + } + + /* + * TTL, Class, Type. + */ + T(x = ns_format_ttl(ttl, buf, buflen)); + addlen(x, &buf, &buflen); + len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type))); + T(addstr(tmp, len, &buf, &buflen)); + T(spaced = addtab(x + len, 16, spaced, &buf, &buflen)); + + /* + * RData. + */ + switch (type) { + case ns_t_a: + if (rdlen != (size_t)NS_INADDRSZ) + goto formerr; + (void) inet_ntop(AF_INET, rdata, buf, buflen); + addlen(strlen(buf), &buf, &buflen); + break; + + case ns_t_cname: + case ns_t_mb: + case ns_t_mg: + case ns_t_mr: + case ns_t_ns: + case ns_t_ptr: + case ns_t_dname: + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + break; + + case ns_t_hinfo: + case ns_t_isdn: + /* First word. */ + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + T(addstr(" ", 1, &buf, &buflen)); + + + /* Second word, optional in ISDN records. */ + if (type == ns_t_isdn && rdata == edata) + break; + + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + break; + + case ns_t_soa: { + u_long t; + + /* Server name. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" ", 1, &buf, &buflen)); + + /* Administrator name. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" (\n", 3, &buf, &buflen)); + spaced = 0; + + if ((edata - rdata) != 5*NS_INT32SZ) + goto formerr; + + /* Serial number. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + T(addstr("\t\t\t\t\t", 5, &buf, &buflen)); + len = SPRINTF((tmp, "%lu", t)); + T(addstr(tmp, len, &buf, &buflen)); + T(spaced = addtab(len, 16, spaced, &buf, &buflen)); + T(addstr("; serial\n", 9, &buf, &buflen)); + spaced = 0; + + /* Refresh interval. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + T(addstr("\t\t\t\t\t", 5, &buf, &buflen)); + T(len = ns_format_ttl(t, buf, buflen)); + addlen(len, &buf, &buflen); + T(spaced = addtab(len, 16, spaced, &buf, &buflen)); + T(addstr("; refresh\n", 10, &buf, &buflen)); + spaced = 0; + + /* Retry interval. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + T(addstr("\t\t\t\t\t", 5, &buf, &buflen)); + T(len = ns_format_ttl(t, buf, buflen)); + addlen(len, &buf, &buflen); + T(spaced = addtab(len, 16, spaced, &buf, &buflen)); + T(addstr("; retry\n", 8, &buf, &buflen)); + spaced = 0; + + /* Expiry. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + T(addstr("\t\t\t\t\t", 5, &buf, &buflen)); + T(len = ns_format_ttl(t, buf, buflen)); + addlen(len, &buf, &buflen); + T(spaced = addtab(len, 16, spaced, &buf, &buflen)); + T(addstr("; expiry\n", 9, &buf, &buflen)); + spaced = 0; + + /* Minimum TTL. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + T(addstr("\t\t\t\t\t", 5, &buf, &buflen)); + T(len = ns_format_ttl(t, buf, buflen)); + addlen(len, &buf, &buflen); + T(addstr(" )", 2, &buf, &buflen)); + T(spaced = addtab(len, 16, spaced, &buf, &buflen)); + T(addstr("; minimum\n", 10, &buf, &buflen)); + + break; + } + + case ns_t_mx: + case ns_t_afsdb: + case ns_t_rt: { + u_int t; + + if (rdlen < (size_t)NS_INT16SZ) + goto formerr; + + /* Priority. */ + t = ns_get16(rdata); + rdata += NS_INT16SZ; + len = SPRINTF((tmp, "%u ", t)); + T(addstr(tmp, len, &buf, &buflen)); + + /* Target. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + break; + } + + case ns_t_px: { + u_int t; + + if (rdlen < (size_t)NS_INT16SZ) + goto formerr; + + /* Priority. */ + t = ns_get16(rdata); + rdata += NS_INT16SZ; + len = SPRINTF((tmp, "%u ", t)); + T(addstr(tmp, len, &buf, &buflen)); + + /* Name1. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" ", 1, &buf, &buflen)); + + /* Name2. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + break; + } + + case ns_t_x25: + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + break; + + case ns_t_txt: + while (rdata < edata) { + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + if (rdata < edata) + T(addstr(" ", 1, &buf, &buflen)); + } + break; + + case ns_t_nsap: { + char t[2+255*3]; + + (void) inet_nsap_ntoa(rdlen, rdata, t); + T(addstr(t, strlen(t), &buf, &buflen)); + break; + } + + case ns_t_aaaa: + if (rdlen != (size_t)NS_IN6ADDRSZ) + goto formerr; + (void) inet_ntop(AF_INET6, rdata, buf, buflen); + addlen(strlen(buf), &buf, &buflen); + break; + + case ns_t_loc: { + char t[255]; + + /* XXX protocol format checking? */ + (void) loc_ntoa(rdata, t); + T(addstr(t, strlen(t), &buf, &buflen)); + break; + } + + case ns_t_naptr: { + u_int order, preference; + char t[50]; + + if (rdlen < 2U*NS_INT16SZ) + goto formerr; + + /* Order, Precedence. */ + order = ns_get16(rdata); rdata += NS_INT16SZ; + preference = ns_get16(rdata); rdata += NS_INT16SZ; + len = SPRINTF((t, "%u %u ", order, preference)); + T(addstr(t, len, &buf, &buflen)); + + /* Flags. */ + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + T(addstr(" ", 1, &buf, &buflen)); + + /* Service. */ + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + T(addstr(" ", 1, &buf, &buflen)); + + /* Regexp. */ + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len < 0) + return (-1); + if (len == 0) + goto formerr; + rdata += len; + T(addstr(" ", 1, &buf, &buflen)); + + /* Server. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + break; + } + + case ns_t_srv: { + u_int priority, weight, port; + char t[50]; + + if (rdlen < 3U*NS_INT16SZ) + goto formerr; + + /* Priority, Weight, Port. */ + priority = ns_get16(rdata); rdata += NS_INT16SZ; + weight = ns_get16(rdata); rdata += NS_INT16SZ; + port = ns_get16(rdata); rdata += NS_INT16SZ; + len = SPRINTF((t, "%u %u %u ", priority, weight, port)); + T(addstr(t, len, &buf, &buflen)); + + /* Server. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + break; + } + + case ns_t_minfo: + case ns_t_rp: + /* Name1. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" ", 1, &buf, &buflen)); + + /* Name2. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + break; + + case ns_t_wks: { + int n, lcnt; + + if (rdlen < 1U + NS_INT32SZ) + goto formerr; + + /* Address. */ + (void) inet_ntop(AF_INET, rdata, buf, buflen); + addlen(strlen(buf), &buf, &buflen); + rdata += NS_INADDRSZ; + + /* Protocol. */ + len = SPRINTF((tmp, " %u ( ", *rdata)); + T(addstr(tmp, len, &buf, &buflen)); + rdata += NS_INT8SZ; + + /* Bit map. */ + n = 0; + lcnt = 0; + while (rdata < edata) { + u_int c = *rdata++; + do { + if (c & 0200) { + if (lcnt == 0) { + T(addstr("\n\t\t\t\t", 5, + &buf, &buflen)); + lcnt = 10; + spaced = 0; + } + len = SPRINTF((tmp, "%d ", n)); + T(addstr(tmp, len, &buf, &buflen)); + lcnt--; + } + c <<= 1; + } while (++n & 07); + } + T(addstr(")", 1, &buf, &buflen)); + + break; + } + + case ns_t_key: { + char base64_key[NS_MD5RSA_MAX_BASE64]; + u_int keyflags, protocol, algorithm, key_id; + const char *leader; + int n; + + if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ) + goto formerr; + + /* Key flags, Protocol, Algorithm. */ + key_id = dst_s_dns_key_id(rdata, edata-rdata); + keyflags = ns_get16(rdata); rdata += NS_INT16SZ; + protocol = *rdata++; + algorithm = *rdata++; + len = SPRINTF((tmp, "0x%04x %u %u", + keyflags, protocol, algorithm)); + T(addstr(tmp, len, &buf, &buflen)); + + /* Public key data. */ + len = b64_ntop(rdata, edata - rdata, + base64_key, sizeof base64_key); + if (len < 0) + goto formerr; + if (len > 15) { + T(addstr(" (", 2, &buf, &buflen)); + leader = "\n\t\t"; + spaced = 0; + } else + leader = " "; + for (n = 0; n < len; n += 48) { + T(addstr(leader, strlen(leader), &buf, &buflen)); + T(addstr(base64_key + n, MIN(len - n, 48), + &buf, &buflen)); + } + if (len > 15) + T(addstr(" )", 2, &buf, &buflen)); + n = SPRINTF((tmp, " ; key_tag= %u", key_id)); + T(addstr(tmp, n, &buf, &buflen)); + + break; + } + + case ns_t_sig: { + char base64_key[NS_MD5RSA_MAX_BASE64]; + u_int type, algorithm, labels, footprint; + const char *leader; + u_long t; + int n; + + if (rdlen < 22U) + goto formerr; + + /* Type covered, Algorithm, Label count, Original TTL. */ + type = ns_get16(rdata); rdata += NS_INT16SZ; + algorithm = *rdata++; + labels = *rdata++; + t = ns_get32(rdata); rdata += NS_INT32SZ; + len = SPRINTF((tmp, "%s %d %d %lu ", + p_type(type), algorithm, labels, t)); + T(addstr(tmp, len, &buf, &buflen)); + if (labels > (u_int)dn_count_labels(name)) + goto formerr; + + /* Signature expiry. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + len = SPRINTF((tmp, "%s ", p_secstodate(t))); + T(addstr(tmp, len, &buf, &buflen)); + + /* Time signed. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + len = SPRINTF((tmp, "%s ", p_secstodate(t))); + T(addstr(tmp, len, &buf, &buflen)); + + /* Signature Footprint. */ + footprint = ns_get16(rdata); rdata += NS_INT16SZ; + len = SPRINTF((tmp, "%u ", footprint)); + T(addstr(tmp, len, &buf, &buflen)); + + /* Signer's name. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + /* Signature. */ + len = b64_ntop(rdata, edata - rdata, + base64_key, sizeof base64_key); + if (len > 15) { + T(addstr(" (", 2, &buf, &buflen)); + leader = "\n\t\t"; + spaced = 0; + } else + leader = " "; + if (len < 0) + goto formerr; + for (n = 0; n < len; n += 48) { + T(addstr(leader, strlen(leader), &buf, &buflen)); + T(addstr(base64_key + n, MIN(len - n, 48), + &buf, &buflen)); + } + if (len > 15) + T(addstr(" )", 2, &buf, &buflen)); + break; + } + + case ns_t_nxt: { + int n, c; + + /* Next domain name. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + /* Type bit map. */ + n = edata - rdata; + for (c = 0; c < n*8; c++) + if (NS_NXT_BIT_ISSET(c, rdata)) { + len = SPRINTF((tmp, " %s", p_type(c))); + T(addstr(tmp, len, &buf, &buflen)); + } + break; + } + + case ns_t_cert: { + u_int c_type, key_tag, alg; + int n; + unsigned int siz; + char base64_cert[8192], tmp[40]; + const char *leader; + + c_type = ns_get16(rdata); rdata += NS_INT16SZ; + key_tag = ns_get16(rdata); rdata += NS_INT16SZ; + alg = (u_int) *rdata++; + + len = SPRINTF((tmp, "%d %d %d ", c_type, key_tag, alg)); + T(addstr(tmp, len, &buf, &buflen)); + siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */ + if (siz > sizeof(base64_cert) * 3/4) { + const char *str = "record too long to print"; + T(addstr(str, strlen(str), &buf, &buflen)); + } + else { + len = b64_ntop(rdata, edata-rdata, base64_cert, siz); + + if (len < 0) + goto formerr; + else if (len > 15) { + T(addstr(" (", 2, &buf, &buflen)); + leader = "\n\t\t"; + spaced = 0; + } + else + leader = " "; + + for (n = 0; n < len; n += 48) { + T(addstr(leader, strlen(leader), + &buf, &buflen)); + T(addstr(base64_cert + n, MIN(len - n, 48), + &buf, &buflen)); + } + if (len > 15) + T(addstr(" )", 2, &buf, &buflen)); + } + break; + } + + case ns_t_tkey: { + /* KJD - need to complete this */ + u_long t; + int mode, err, keysize; + + /* Algorithm name. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" ", 1, &buf, &buflen)); + + /* Inception. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + len = SPRINTF((tmp, "%s ", p_secstodate(t))); + T(addstr(tmp, len, &buf, &buflen)); + + /* Experation. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + len = SPRINTF((tmp, "%s ", p_secstodate(t))); + T(addstr(tmp, len, &buf, &buflen)); + + /* Mode , Error, Key Size. */ + /* Priority, Weight, Port. */ + mode = ns_get16(rdata); rdata += NS_INT16SZ; + err = ns_get16(rdata); rdata += NS_INT16SZ; + keysize = ns_get16(rdata); rdata += NS_INT16SZ; + len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize)); + T(addstr(tmp, len, &buf, &buflen)); + + /* XXX need to dump key, print otherdata length & other data */ + break; + } + + case ns_t_tsig: { + /* BEW - need to complete this */ + int n; + + T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" ", 1, &buf, &buflen)); + rdata += 8; /*%< time */ + n = ns_get16(rdata); rdata += INT16SZ; + rdata += n; /*%< sig */ + n = ns_get16(rdata); rdata += INT16SZ; /*%< original id */ + sprintf(buf, "%d", ns_get16(rdata)); + rdata += INT16SZ; + addlen(strlen(buf), &buf, &buflen); + break; + } + + case ns_t_a6: { + struct in6_addr a; + int pbyte, pbit; + + /* prefix length */ + if (rdlen == 0U) goto formerr; + len = SPRINTF((tmp, "%d ", *rdata)); + T(addstr(tmp, len, &buf, &buflen)); + pbit = *rdata; + if (pbit > 128) goto formerr; + pbyte = (pbit & ~7) / 8; + rdata++; + + /* address suffix: provided only when prefix len != 128 */ + if (pbit < 128) { + if (rdata + pbyte >= edata) goto formerr; + memset(&a, 0, sizeof(a)); + memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte); + (void) inet_ntop(AF_INET6, &a, buf, buflen); + addlen(strlen(buf), &buf, &buflen); + rdata += sizeof(a) - pbyte; + } + + /* prefix name: provided only when prefix len > 0 */ + if (pbit == 0) + break; + if (rdata >= edata) goto formerr; + T(addstr(" ", 1, &buf, &buflen)); + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + break; + } + + case ns_t_opt: { + len = SPRINTF((tmp, "%u bytes", class)); + T(addstr(tmp, len, &buf, &buflen)); + break; + } + + default: + comment = "unknown RR type"; + goto hexify; + } + return (buf - obuf); + formerr: + comment = "RR format error"; + hexify: { + int n, m; + char *p; + + len = SPRINTF((tmp, "\\# %u%s\t; %s", (unsigned)(edata - rdata), + rdlen != 0U ? " (" : "", comment)); + T(addstr(tmp, len, &buf, &buflen)); + while (rdata < edata) { + p = tmp; + p += SPRINTF((p, "\n\t")); + spaced = 0; + n = MIN(16, edata - rdata); + for (m = 0; m < n; m++) + p += SPRINTF((p, "%02x ", rdata[m])); + T(addstr(tmp, p - tmp, &buf, &buflen)); + if (n < 16) { + T(addstr(")", 1, &buf, &buflen)); + T(addtab(p - tmp + 1, 48, spaced, &buf, &buflen)); + } + p = tmp; + p += SPRINTF((p, "; ")); + for (m = 0; m < n; m++) + *p++ = (isascii(rdata[m]) && isprint(rdata[m])) + ? rdata[m] + : '.'; + T(addstr(tmp, p - tmp, &buf, &buflen)); + rdata += n; + } + return (buf - obuf); + } +} + +/* Private. */ + +/*% + * size_t + * prune_origin(name, origin) + * Find out if the name is at or under the current origin. + * return: + * Number of characters in name before start of origin, + * or length of name if origin does not match. + * notes: + * This function should share code with samedomain(). + */ +static size_t +prune_origin(const char *name, const char *origin) { + const char *oname = name; + + while (*name != '\0') { + if (origin != NULL && ns_samename(name, origin) == 1) + return (name - oname - (name > oname)); + while (*name != '\0') { + if (*name == '\\') { + name++; + /* XXX need to handle \nnn form. */ + if (*name == '\0') + break; + } else if (*name == '.') { + name++; + break; + } + name++; + } + } + return (name - oname); +} + +/*% + * int + * charstr(rdata, edata, buf, buflen) + * Format a into the presentation buffer. + * return: + * Number of rdata octets consumed + * 0 for protocol format error + * -1 for output buffer error + * side effects: + * buffer is advanced on success. + */ +static int +charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) { + const u_char *odata = rdata; + size_t save_buflen = *buflen; + char *save_buf = *buf; + + if (addstr("\"", 1, buf, buflen) < 0) + goto enospc; + if (rdata < edata) { + int n = *rdata; + + if (rdata + 1 + n <= edata) { + rdata++; + while (n-- > 0) { + if (strchr("\n\"\\", *rdata) != NULL) + if (addstr("\\", 1, buf, buflen) < 0) + goto enospc; + if (addstr((const char *)rdata, 1, + buf, buflen) < 0) + goto enospc; + rdata++; + } + } + } + if (addstr("\"", 1, buf, buflen) < 0) + goto enospc; + return (rdata - odata); + enospc: + errno = ENOSPC; + *buf = save_buf; + *buflen = save_buflen; + return (-1); +} + +static int +addname(const u_char *msg, size_t msglen, + const u_char **pp, const char *origin, + char **buf, size_t *buflen) +{ + size_t newlen, save_buflen = *buflen; + char *save_buf = *buf; + int n; + + n = dn_expand(msg, msg + msglen, *pp, *buf, *buflen); + if (n < 0) + goto enospc; /*%< Guess. */ + newlen = prune_origin(*buf, origin); + if (**buf == '\0') { + goto root; + } else if (newlen == 0U) { + /* Use "@" instead of name. */ + if (newlen + 2 > *buflen) + goto enospc; /* No room for "@\0". */ + (*buf)[newlen++] = '@'; + (*buf)[newlen] = '\0'; + } else { + if (((origin == NULL || origin[0] == '\0') || + (origin[0] != '.' && origin[1] != '\0' && + (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') { + /* No trailing dot. */ + root: + if (newlen + 2 > *buflen) + goto enospc; /* No room for ".\0". */ + (*buf)[newlen++] = '.'; + (*buf)[newlen] = '\0'; + } + } + *pp += n; + addlen(newlen, buf, buflen); + **buf = '\0'; + return (newlen); + enospc: + errno = ENOSPC; + *buf = save_buf; + *buflen = save_buflen; + return (-1); +} + +static void +addlen(size_t len, char **buf, size_t *buflen) { + INSIST(len <= *buflen); + *buf += len; + *buflen -= len; +} + +static int +addstr(const char *src, size_t len, char **buf, size_t *buflen) { + if (len >= *buflen) { + errno = ENOSPC; + return (-1); + } + memcpy(*buf, src, len); + addlen(len, buf, buflen); + **buf = '\0'; + return (0); +} + +static int +addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) { + size_t save_buflen = *buflen; + char *save_buf = *buf; + int t; + + if (spaced || len >= target - 1) { + T(addstr(" ", 2, buf, buflen)); + spaced = 1; + } else { + for (t = (target - len - 1) / 8; t >= 0; t--) + if (addstr("\t", 1, buf, buflen) < 0) { + *buflen = save_buflen; + *buf = save_buf; + return (-1); + } + spaced = 0; + } + return (spaced); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/nameser/ns_samedomain.c b/contrib/bind-9.5.2/lib/bind/nameser/ns_samedomain.c new file mode 100644 index 0000000000..5e9f5cab54 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/nameser/ns_samedomain.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1995,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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 lint +static const char rcsid[] = "$Id: ns_samedomain.c,v 1.6 2005/04/27 04:56:40 sra Exp $"; +#endif + +#include "port_before.h" + +#include +#include +#include +#include + +#include "port_after.h" + +/*% + * Check whether a name belongs to a domain. + * + * Inputs: + *\li a - the domain whose ancestory is being verified + *\li b - the potential ancestor we're checking against + * + * Return: + *\li boolean - is a at or below b? + * + * Notes: + *\li Trailing dots are first removed from name and domain. + * Always compare complete subdomains, not only whether the + * domain name is the trailing string of the given name. + * + *\li "host.foobar.top" lies in "foobar.top" and in "top" and in "" + * but NOT in "bar.top" + */ + +int +ns_samedomain(const char *a, const char *b) { + size_t la, lb; + int diff, i, escaped; + const char *cp; + + la = strlen(a); + lb = strlen(b); + + /* Ignore a trailing label separator (i.e. an unescaped dot) in 'a'. */ + if (la != 0U && a[la - 1] == '.') { + escaped = 0; + /* Note this loop doesn't get executed if la==1. */ + for (i = la - 2; i >= 0; i--) + if (a[i] == '\\') { + if (escaped) + escaped = 0; + else + escaped = 1; + } else + break; + if (!escaped) + la--; + } + + /* Ignore a trailing label separator (i.e. an unescaped dot) in 'b'. */ + if (lb != 0U && b[lb - 1] == '.') { + escaped = 0; + /* note this loop doesn't get executed if lb==1 */ + for (i = lb - 2; i >= 0; i--) + if (b[i] == '\\') { + if (escaped) + escaped = 0; + else + escaped = 1; + } else + break; + if (!escaped) + lb--; + } + + /* lb == 0 means 'b' is the root domain, so 'a' must be in 'b'. */ + if (lb == 0U) + return (1); + + /* 'b' longer than 'a' means 'a' can't be in 'b'. */ + if (lb > la) + return (0); + + /* 'a' and 'b' being equal at this point indicates sameness. */ + if (lb == la) + return (strncasecmp(a, b, lb) == 0); + + /* Ok, we know la > lb. */ + + diff = la - lb; + + /* + * If 'a' is only 1 character longer than 'b', then it can't be + * a subdomain of 'b' (because of the need for the '.' label + * separator). + */ + if (diff < 2) + return (0); + + /* + * If the character before the last 'lb' characters of 'b' + * isn't '.', then it can't be a match (this lets us avoid + * having "foobar.com" match "bar.com"). + */ + if (a[diff - 1] != '.') + return (0); + + /* + * We're not sure about that '.', however. It could be escaped + * and thus not a really a label separator. + */ + escaped = 0; + for (i = diff - 2; i >= 0; i--) + if (a[i] == '\\') { + if (escaped) + escaped = 0; + else + escaped = 1; + } else + break; + if (escaped) + return (0); + + /* Now compare aligned trailing substring. */ + cp = a + diff; + return (strncasecmp(cp, b, lb) == 0); +} + +/*% + * is "a" a subdomain of "b"? + */ +int +ns_subdomain(const char *a, const char *b) { + return (ns_samename(a, b) != 1 && ns_samedomain(a, b)); +} + +/*% + * make a canonical copy of domain name "src" + * + * notes: + * \code + * foo -> foo. + * foo. -> foo. + * foo.. -> foo. + * foo\. -> foo\.. + * foo\\. -> foo\\. + * \endcode + */ + +int +ns_makecanon(const char *src, char *dst, size_t dstsize) { + size_t n = strlen(src); + + if (n + sizeof "." > dstsize) { /*%< Note: sizeof == 2 */ + errno = EMSGSIZE; + return (-1); + } + strcpy(dst, src); + while (n >= 1U && dst[n - 1] == '.') /*%< Ends in "." */ + if (n >= 2U && dst[n - 2] == '\\' && /*%< Ends in "\." */ + (n < 3U || dst[n - 3] != '\\')) /*%< But not "\\." */ + break; + else + dst[--n] = '\0'; + dst[n++] = '.'; + dst[n] = '\0'; + return (0); +} + +/*% + * determine whether domain name "a" is the same as domain name "b" + * + * return: + *\li -1 on error + *\li 0 if names differ + *\li 1 if names are the same + */ + +int +ns_samename(const char *a, const char *b) { + char ta[NS_MAXDNAME], tb[NS_MAXDNAME]; + + if (ns_makecanon(a, ta, sizeof ta) < 0 || + ns_makecanon(b, tb, sizeof tb) < 0) + return (-1); + if (strcasecmp(ta, tb) == 0) + return (1); + else + return (0); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/nameser/ns_sign.c b/contrib/bind-9.5.2/lib/bind/nameser/ns_sign.c new file mode 100644 index 0000000000..5748a090d9 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/nameser/ns_sign.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1999 by Internet Software Consortium, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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 lint +static const char rcsid[] = "$Id: ns_sign.c,v 1.6 2006/03/09 23:57:56 marka Exp $"; +#endif + +/* Import. */ + +#include "port_before.h" +#include "fd_setsize.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "port_after.h" + +#define BOUNDS_CHECK(ptr, count) \ + do { \ + if ((ptr) + (count) > eob) { \ + errno = EMSGSIZE; \ + return(NS_TSIG_ERROR_NO_SPACE); \ + } \ + } while (0) + +/*% + * ns_sign + * + * Parameters: + *\li msg message to be sent + *\li msglen input - length of message + * output - length of signed message + *\li msgsize length of buffer containing message + *\li error value to put in the error field + *\li key tsig key used for signing + *\li querysig (response), the signature in the query + *\li querysiglen (response), the length of the signature in the query + *\li sig a buffer to hold the generated signature + *\li siglen input - length of signature buffer + * output - length of signature + * + * Errors: + *\li - bad input data (-1) + *\li - bad key / sign failed (-BADKEY) + *\li - not enough space (NS_TSIG_ERROR_NO_SPACE) + */ +int +ns_sign(u_char *msg, int *msglen, int msgsize, int error, void *k, + const u_char *querysig, int querysiglen, u_char *sig, int *siglen, + time_t in_timesigned) +{ + return(ns_sign2(msg, msglen, msgsize, error, k, + querysig, querysiglen, sig, siglen, + in_timesigned, NULL, NULL)); +} + +int +ns_sign2(u_char *msg, int *msglen, int msgsize, int error, void *k, + const u_char *querysig, int querysiglen, u_char *sig, int *siglen, + time_t in_timesigned, u_char **dnptrs, u_char **lastdnptr) +{ + HEADER *hp = (HEADER *)msg; + DST_KEY *key = (DST_KEY *)k; + u_char *cp, *eob; + u_char *lenp; + u_char *alg; + int n; + time_t timesigned; + u_char name[NS_MAXCDNAME]; + + dst_init(); + if (msg == NULL || msglen == NULL || sig == NULL || siglen == NULL) + return (-1); + + cp = msg + *msglen; + eob = msg + msgsize; + + /* Name. */ + if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { + n = ns_name_pton(key->dk_key_name, name, sizeof name); + if (n != -1) + n = ns_name_pack(name, cp, eob - cp, + (const u_char **)dnptrs, + (const u_char **)lastdnptr); + + } else { + n = ns_name_pton("", name, sizeof name); + if (n != -1) + n = ns_name_pack(name, cp, eob - cp, NULL, NULL); + } + if (n < 0) + return (NS_TSIG_ERROR_NO_SPACE); + cp += n; + + /* Type, class, ttl, length (not filled in yet). */ + BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ); + PUTSHORT(ns_t_tsig, cp); + PUTSHORT(ns_c_any, cp); + PUTLONG(0, cp); /*%< TTL */ + lenp = cp; + cp += 2; + + /* Alg. */ + if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { + if (key->dk_alg != KEY_HMAC_MD5) + return (-ns_r_badkey); + n = dn_comp(NS_TSIG_ALG_HMAC_MD5, cp, eob - cp, NULL, NULL); + } + else + n = dn_comp("", cp, eob - cp, NULL, NULL); + if (n < 0) + return (NS_TSIG_ERROR_NO_SPACE); + alg = cp; + cp += n; + + /* Time. */ + BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); + PUTSHORT(0, cp); + timesigned = time(NULL); + if (error != ns_r_badtime) + PUTLONG(timesigned, cp); + else + PUTLONG(in_timesigned, cp); + PUTSHORT(NS_TSIG_FUDGE, cp); + + /* Compute the signature. */ + if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { + void *ctx; + u_char buf[NS_MAXCDNAME], *cp2; + int n; + + dst_sign_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0); + + /* Digest the query signature, if this is a response. */ + if (querysiglen > 0 && querysig != NULL) { + u_int16_t len_n = htons(querysiglen); + dst_sign_data(SIG_MODE_UPDATE, key, &ctx, + (u_char *)&len_n, INT16SZ, NULL, 0); + dst_sign_data(SIG_MODE_UPDATE, key, &ctx, + querysig, querysiglen, NULL, 0); + } + + /* Digest the message. */ + dst_sign_data(SIG_MODE_UPDATE, key, &ctx, msg, *msglen, + NULL, 0); + + /* Digest the key name. */ + n = ns_name_ntol(name, buf, sizeof(buf)); + INSIST(n > 0); + dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); + + /* Digest the class and TTL. */ + cp2 = buf; + PUTSHORT(ns_c_any, cp2); + PUTLONG(0, cp2); + dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, cp2-buf, + NULL, 0); + + /* Digest the algorithm. */ + n = ns_name_ntol(alg, buf, sizeof(buf)); + INSIST(n > 0); + dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); + + /* Digest the time signed, fudge, error, and other data */ + cp2 = buf; + PUTSHORT(0, cp2); /*%< Top 16 bits of time */ + if (error != ns_r_badtime) + PUTLONG(timesigned, cp2); + else + PUTLONG(in_timesigned, cp2); + PUTSHORT(NS_TSIG_FUDGE, cp2); + PUTSHORT(error, cp2); /*%< Error */ + if (error != ns_r_badtime) + PUTSHORT(0, cp2); /*%< Other data length */ + else { + PUTSHORT(INT16SZ+INT32SZ, cp2); /*%< Other data length */ + PUTSHORT(0, cp2); /*%< Top 16 bits of time */ + PUTLONG(timesigned, cp2); + } + dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, cp2-buf, + NULL, 0); + + n = dst_sign_data(SIG_MODE_FINAL, key, &ctx, NULL, 0, + sig, *siglen); + if (n < 0) + return (-ns_r_badkey); + *siglen = n; + } else + *siglen = 0; + + /* Add the signature. */ + BOUNDS_CHECK(cp, INT16SZ + (*siglen)); + PUTSHORT(*siglen, cp); + memcpy(cp, sig, *siglen); + cp += (*siglen); + + /* The original message ID & error. */ + BOUNDS_CHECK(cp, INT16SZ + INT16SZ); + PUTSHORT(ntohs(hp->id), cp); /*%< already in network order */ + PUTSHORT(error, cp); + + /* Other data. */ + BOUNDS_CHECK(cp, INT16SZ); + if (error != ns_r_badtime) + PUTSHORT(0, cp); /*%< Other data length */ + else { + PUTSHORT(INT16SZ+INT32SZ, cp); /*%< Other data length */ + BOUNDS_CHECK(cp, INT32SZ+INT16SZ); + PUTSHORT(0, cp); /*%< Top 16 bits of time */ + PUTLONG(timesigned, cp); + } + + /* Go back and fill in the length. */ + PUTSHORT(cp - lenp - INT16SZ, lenp); + + hp->arcount = htons(ntohs(hp->arcount) + 1); + *msglen = (cp - msg); + return (0); +} + +int +ns_sign_tcp_init(void *k, const u_char *querysig, int querysiglen, + ns_tcp_tsig_state *state) +{ + dst_init(); + if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0) + return (-1); + state->counter = -1; + state->key = k; + if (state->key->dk_alg != KEY_HMAC_MD5) + return (-ns_r_badkey); + if (querysiglen > (int)sizeof(state->sig)) + return (-1); + memcpy(state->sig, querysig, querysiglen); + state->siglen = querysiglen; + return (0); +} + +int +ns_sign_tcp(u_char *msg, int *msglen, int msgsize, int error, + ns_tcp_tsig_state *state, int done) +{ + return (ns_sign_tcp2(msg, msglen, msgsize, error, state, + done, NULL, NULL)); +} + +int +ns_sign_tcp2(u_char *msg, int *msglen, int msgsize, int error, + ns_tcp_tsig_state *state, int done, + u_char **dnptrs, u_char **lastdnptr) +{ + u_char *cp, *eob, *lenp; + u_char buf[MAXDNAME], *cp2; + HEADER *hp = (HEADER *)msg; + time_t timesigned; + int n; + + if (msg == NULL || msglen == NULL || state == NULL) + return (-1); + + state->counter++; + if (state->counter == 0) + return (ns_sign2(msg, msglen, msgsize, error, state->key, + state->sig, state->siglen, + state->sig, &state->siglen, 0, + dnptrs, lastdnptr)); + + if (state->siglen > 0) { + u_int16_t siglen_n = htons(state->siglen); + dst_sign_data(SIG_MODE_INIT, state->key, &state->ctx, + NULL, 0, NULL, 0); + dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, + (u_char *)&siglen_n, INT16SZ, NULL, 0); + dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, + state->sig, state->siglen, NULL, 0); + state->siglen = 0; + } + + dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, msg, *msglen, + NULL, 0); + + if (done == 0 && (state->counter % 100 != 0)) + return (0); + + cp = msg + *msglen; + eob = msg + msgsize; + + /* Name. */ + n = dn_comp(state->key->dk_key_name, cp, eob - cp, dnptrs, lastdnptr); + if (n < 0) + return (NS_TSIG_ERROR_NO_SPACE); + cp += n; + + /* Type, class, ttl, length (not filled in yet). */ + BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ); + PUTSHORT(ns_t_tsig, cp); + PUTSHORT(ns_c_any, cp); + PUTLONG(0, cp); /*%< TTL */ + lenp = cp; + cp += 2; + + /* Alg. */ + n = dn_comp(NS_TSIG_ALG_HMAC_MD5, cp, eob - cp, NULL, NULL); + if (n < 0) + return (NS_TSIG_ERROR_NO_SPACE); + cp += n; + + /* Time. */ + BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); + PUTSHORT(0, cp); + timesigned = time(NULL); + PUTLONG(timesigned, cp); + PUTSHORT(NS_TSIG_FUDGE, cp); + + /* + * Compute the signature. + */ + + /* Digest the time signed and fudge. */ + cp2 = buf; + PUTSHORT(0, cp2); /*%< Top 16 bits of time */ + PUTLONG(timesigned, cp2); + PUTSHORT(NS_TSIG_FUDGE, cp2); + + dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, + buf, cp2 - buf, NULL, 0); + + n = dst_sign_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0, + state->sig, sizeof(state->sig)); + if (n < 0) + return (-ns_r_badkey); + state->siglen = n; + + /* Add the signature. */ + BOUNDS_CHECK(cp, INT16SZ + state->siglen); + PUTSHORT(state->siglen, cp); + memcpy(cp, state->sig, state->siglen); + cp += state->siglen; + + /* The original message ID & error. */ + BOUNDS_CHECK(cp, INT16SZ + INT16SZ); + PUTSHORT(ntohs(hp->id), cp); /*%< already in network order */ + PUTSHORT(error, cp); + + /* Other data. */ + BOUNDS_CHECK(cp, INT16SZ); + PUTSHORT(0, cp); + + /* Go back and fill in the length. */ + PUTSHORT(cp - lenp - INT16SZ, lenp); + + hp->arcount = htons(ntohs(hp->arcount) + 1); + *msglen = (cp - msg); + return (0); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/nameser/ns_ttl.c b/contrib/bind-9.5.2/lib/bind/nameser/ns_ttl.c new file mode 100644 index 0000000000..69c2f83f57 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/nameser/ns_ttl.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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 lint +static const char rcsid[] = "$Id: ns_ttl.c,v 1.4 2005/07/28 06:51:49 marka Exp $"; +#endif + +/* Import. */ + +#include "port_before.h" + +#include + +#include +#include +#include +#include + +#include "port_after.h" + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +/* Forward. */ + +static int fmt1(int t, char s, char **buf, size_t *buflen); + +/* Macros. */ + +#define T(x) if ((x) < 0) return (-1); else (void)NULL + +/* Public. */ + +int +ns_format_ttl(u_long src, char *dst, size_t dstlen) { + char *odst = dst; + int secs, mins, hours, days, weeks, x; + char *p; + + secs = src % 60; src /= 60; + mins = src % 60; src /= 60; + hours = src % 24; src /= 24; + days = src % 7; src /= 7; + weeks = src; src = 0; + + x = 0; + if (weeks) { + T(fmt1(weeks, 'W', &dst, &dstlen)); + x++; + } + if (days) { + T(fmt1(days, 'D', &dst, &dstlen)); + x++; + } + if (hours) { + T(fmt1(hours, 'H', &dst, &dstlen)); + x++; + } + if (mins) { + T(fmt1(mins, 'M', &dst, &dstlen)); + x++; + } + if (secs || !(weeks || days || hours || mins)) { + T(fmt1(secs, 'S', &dst, &dstlen)); + x++; + } + + if (x > 1) { + int ch; + + for (p = odst; (ch = *p) != '\0'; p++) + if (isascii(ch) && isupper(ch)) + *p = tolower(ch); + } + + return (dst - odst); +} + +int +ns_parse_ttl(const char *src, u_long *dst) { + u_long ttl, tmp; + int ch, digits, dirty; + + ttl = 0; + tmp = 0; + digits = 0; + dirty = 0; + while ((ch = *src++) != '\0') { + if (!isascii(ch) || !isprint(ch)) + goto einval; + if (isdigit(ch)) { + tmp *= 10; + tmp += (ch - '0'); + digits++; + continue; + } + if (digits == 0) + goto einval; + if (islower(ch)) + ch = toupper(ch); + switch (ch) { + case 'W': tmp *= 7; + case 'D': tmp *= 24; + case 'H': tmp *= 60; + case 'M': tmp *= 60; + case 'S': break; + default: goto einval; + } + ttl += tmp; + tmp = 0; + digits = 0; + dirty = 1; + } + if (digits > 0) { + if (dirty) + goto einval; + else + ttl += tmp; + } else if (!dirty) + goto einval; + *dst = ttl; + return (0); + + einval: + errno = EINVAL; + return (-1); +} + +/* Private. */ + +static int +fmt1(int t, char s, char **buf, size_t *buflen) { + char tmp[50]; + size_t len; + + len = SPRINTF((tmp, "%d%c", t, s)); + if (len + 1 > *buflen) + return (-1); + strcpy(*buf, tmp); + *buf += len; + *buflen -= len; + return (0); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/nameser/ns_verify.c b/contrib/bind-9.5.2/lib/bind/nameser/ns_verify.c new file mode 100644 index 0000000000..97c012db8f --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/nameser/ns_verify.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1999 by Internet Software Consortium, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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 lint +static const char rcsid[] = "$Id: ns_verify.c,v 1.5 2006/03/09 23:57:56 marka Exp $"; +#endif + +/* Import. */ + +#include "port_before.h" +#include "fd_setsize.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "port_after.h" + +/* Private. */ + +#define BOUNDS_CHECK(ptr, count) \ + do { \ + if ((ptr) + (count) > eom) { \ + return (NS_TSIG_ERROR_FORMERR); \ + } \ + } while (0) + +/* Public. */ + +u_char * +ns_find_tsig(u_char *msg, u_char *eom) { + HEADER *hp = (HEADER *)msg; + int n, type; + u_char *cp = msg, *start; + + if (msg == NULL || eom == NULL || msg > eom) + return (NULL); + + if (cp + HFIXEDSZ >= eom) + return (NULL); + + if (hp->arcount == 0) + return (NULL); + + cp += HFIXEDSZ; + + n = ns_skiprr(cp, eom, ns_s_qd, ntohs(hp->qdcount)); + if (n < 0) + return (NULL); + cp += n; + + n = ns_skiprr(cp, eom, ns_s_an, ntohs(hp->ancount)); + if (n < 0) + return (NULL); + cp += n; + + n = ns_skiprr(cp, eom, ns_s_ns, ntohs(hp->nscount)); + if (n < 0) + return (NULL); + cp += n; + + n = ns_skiprr(cp, eom, ns_s_ar, ntohs(hp->arcount) - 1); + if (n < 0) + return (NULL); + cp += n; + + start = cp; + n = dn_skipname(cp, eom); + if (n < 0) + return (NULL); + cp += n; + if (cp + INT16SZ >= eom) + return (NULL); + + GETSHORT(type, cp); + if (type != ns_t_tsig) + return (NULL); + return (start); +} + +/* ns_verify + * + * Parameters: + *\li statp res stuff + *\li msg received message + *\li msglen length of message + *\li key tsig key used for verifying. + *\li querysig (response), the signature in the query + *\li querysiglen (response), the length of the signature in the query + *\li sig (query), a buffer to hold the signature + *\li siglen (query), input - length of signature buffer + * output - length of signature + * + * Errors: + *\li - bad input (-1) + *\li - invalid dns message (NS_TSIG_ERROR_FORMERR) + *\li - TSIG is not present (NS_TSIG_ERROR_NO_TSIG) + *\li - key doesn't match (-ns_r_badkey) + *\li - TSIG verification fails with BADKEY (-ns_r_badkey) + *\li - TSIG verification fails with BADSIG (-ns_r_badsig) + *\li - TSIG verification fails with BADTIME (-ns_r_badtime) + *\li - TSIG verification succeeds, error set to BAKEY (ns_r_badkey) + *\li - TSIG verification succeeds, error set to BADSIG (ns_r_badsig) + *\li - TSIG verification succeeds, error set to BADTIME (ns_r_badtime) + */ +int +ns_verify(u_char *msg, int *msglen, void *k, + const u_char *querysig, int querysiglen, u_char *sig, int *siglen, + time_t *timesigned, int nostrip) +{ + HEADER *hp = (HEADER *)msg; + DST_KEY *key = (DST_KEY *)k; + u_char *cp = msg, *eom; + char name[MAXDNAME], alg[MAXDNAME]; + u_char *recstart, *rdatastart; + u_char *sigstart, *otherstart; + int n; + int error; + u_int16_t type, length; + u_int16_t fudge, sigfieldlen, otherfieldlen; + + dst_init(); + if (msg == NULL || msglen == NULL || *msglen < 0) + return (-1); + + eom = msg + *msglen; + + recstart = ns_find_tsig(msg, eom); + if (recstart == NULL) + return (NS_TSIG_ERROR_NO_TSIG); + + cp = recstart; + + /* Read the key name. */ + n = dn_expand(msg, eom, cp, name, MAXDNAME); + if (n < 0) + return (NS_TSIG_ERROR_FORMERR); + cp += n; + + /* Read the type. */ + BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ); + GETSHORT(type, cp); + if (type != ns_t_tsig) + return (NS_TSIG_ERROR_NO_TSIG); + + /* Skip the class and TTL, save the length. */ + cp += INT16SZ + INT32SZ; + GETSHORT(length, cp); + if (eom - cp != length) + return (NS_TSIG_ERROR_FORMERR); + + /* Read the algorithm name. */ + rdatastart = cp; + n = dn_expand(msg, eom, cp, alg, MAXDNAME); + if (n < 0) + return (NS_TSIG_ERROR_FORMERR); + if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1) + return (-ns_r_badkey); + cp += n; + + /* Read the time signed and fudge. */ + BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); + cp += INT16SZ; + GETLONG((*timesigned), cp); + GETSHORT(fudge, cp); + + /* Read the signature. */ + BOUNDS_CHECK(cp, INT16SZ); + GETSHORT(sigfieldlen, cp); + BOUNDS_CHECK(cp, sigfieldlen); + sigstart = cp; + cp += sigfieldlen; + + /* Skip id and read error. */ + BOUNDS_CHECK(cp, 2*INT16SZ); + cp += INT16SZ; + GETSHORT(error, cp); + + /* Parse the other data. */ + BOUNDS_CHECK(cp, INT16SZ); + GETSHORT(otherfieldlen, cp); + BOUNDS_CHECK(cp, otherfieldlen); + otherstart = cp; + cp += otherfieldlen; + + if (cp != eom) + return (NS_TSIG_ERROR_FORMERR); + + /* Verify that the key used is OK. */ + if (key != NULL) { + if (key->dk_alg != KEY_HMAC_MD5) + return (-ns_r_badkey); + if (error != ns_r_badsig && error != ns_r_badkey) { + if (ns_samename(key->dk_key_name, name) != 1) + return (-ns_r_badkey); + } + } + + hp->arcount = htons(ntohs(hp->arcount) - 1); + + /* + * Do the verification. + */ + + if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { + void *ctx; + u_char buf[MAXDNAME]; + u_char buf2[MAXDNAME]; + + /* Digest the query signature, if this is a response. */ + dst_verify_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0); + if (querysiglen > 0 && querysig != NULL) { + u_int16_t len_n = htons(querysiglen); + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, + (u_char *)&len_n, INT16SZ, NULL, 0); + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, + querysig, querysiglen, NULL, 0); + } + + /* Digest the message. */ + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, msg, recstart - msg, + NULL, 0); + + /* Digest the key name. */ + n = ns_name_pton(name, buf2, sizeof(buf2)); + if (n < 0) + return (-1); + n = ns_name_ntol(buf2, buf, sizeof(buf)); + if (n < 0) + return (-1); + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); + + /* Digest the class and TTL. */ + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, + recstart + dn_skipname(recstart, eom) + INT16SZ, + INT16SZ + INT32SZ, NULL, 0); + + /* Digest the algorithm. */ + n = ns_name_pton(alg, buf2, sizeof(buf2)); + if (n < 0) + return (-1); + n = ns_name_ntol(buf2, buf, sizeof(buf)); + if (n < 0) + return (-1); + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); + + /* Digest the time signed and fudge. */ + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, + rdatastart + dn_skipname(rdatastart, eom), + INT16SZ + INT32SZ + INT16SZ, NULL, 0); + + /* Digest the error and other data. */ + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, + otherstart - INT16SZ - INT16SZ, + otherfieldlen + INT16SZ + INT16SZ, NULL, 0); + + n = dst_verify_data(SIG_MODE_FINAL, key, &ctx, NULL, 0, + sigstart, sigfieldlen); + + if (n < 0) + return (-ns_r_badsig); + + if (sig != NULL && siglen != NULL) { + if (*siglen < sigfieldlen) + return (NS_TSIG_ERROR_NO_SPACE); + memcpy(sig, sigstart, sigfieldlen); + *siglen = sigfieldlen; + } + } else { + if (sigfieldlen > 0) + return (NS_TSIG_ERROR_FORMERR); + if (sig != NULL && siglen != NULL) + *siglen = 0; + } + + /* Reset the counter, since we still need to check for badtime. */ + hp->arcount = htons(ntohs(hp->arcount) + 1); + + /* Verify the time. */ + if (abs((*timesigned) - time(NULL)) > fudge) + return (-ns_r_badtime); + + if (nostrip == 0) { + *msglen = recstart - msg; + hp->arcount = htons(ntohs(hp->arcount) - 1); + } + + if (error != NOERROR) + return (error); + + return (0); +} + +int +ns_verify_tcp_init(void *k, const u_char *querysig, int querysiglen, + ns_tcp_tsig_state *state) +{ + dst_init(); + if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0) + return (-1); + state->counter = -1; + state->key = k; + if (state->key->dk_alg != KEY_HMAC_MD5) + return (-ns_r_badkey); + if (querysiglen > (int)sizeof(state->sig)) + return (-1); + memcpy(state->sig, querysig, querysiglen); + state->siglen = querysiglen; + return (0); +} + +int +ns_verify_tcp(u_char *msg, int *msglen, ns_tcp_tsig_state *state, + int required) +{ + HEADER *hp = (HEADER *)msg; + u_char *recstart, *sigstart; + unsigned int sigfieldlen, otherfieldlen; + u_char *cp, *eom, *cp2; + char name[MAXDNAME], alg[MAXDNAME]; + u_char buf[MAXDNAME]; + int n, type, length, fudge, error; + time_t timesigned; + + if (msg == NULL || msglen == NULL || state == NULL) + return (-1); + + eom = msg + *msglen; + + state->counter++; + if (state->counter == 0) + return (ns_verify(msg, msglen, state->key, + state->sig, state->siglen, + state->sig, &state->siglen, ×igned, 0)); + + if (state->siglen > 0) { + u_int16_t siglen_n = htons(state->siglen); + + dst_verify_data(SIG_MODE_INIT, state->key, &state->ctx, + NULL, 0, NULL, 0); + dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, + (u_char *)&siglen_n, INT16SZ, NULL, 0); + dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, + state->sig, state->siglen, NULL, 0); + state->siglen = 0; + } + + cp = recstart = ns_find_tsig(msg, eom); + + if (recstart == NULL) { + if (required) + return (NS_TSIG_ERROR_NO_TSIG); + dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, + msg, *msglen, NULL, 0); + return (0); + } + + hp->arcount = htons(ntohs(hp->arcount) - 1); + dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, + msg, recstart - msg, NULL, 0); + + /* Read the key name. */ + n = dn_expand(msg, eom, cp, name, MAXDNAME); + if (n < 0) + return (NS_TSIG_ERROR_FORMERR); + cp += n; + + /* Read the type. */ + BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ); + GETSHORT(type, cp); + if (type != ns_t_tsig) + return (NS_TSIG_ERROR_NO_TSIG); + + /* Skip the class and TTL, save the length. */ + cp += INT16SZ + INT32SZ; + GETSHORT(length, cp); + if (eom - cp != length) + return (NS_TSIG_ERROR_FORMERR); + + /* Read the algorithm name. */ + n = dn_expand(msg, eom, cp, alg, MAXDNAME); + if (n < 0) + return (NS_TSIG_ERROR_FORMERR); + if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1) + return (-ns_r_badkey); + cp += n; + + /* Verify that the key used is OK. */ + if ((ns_samename(state->key->dk_key_name, name) != 1 || + state->key->dk_alg != KEY_HMAC_MD5)) + return (-ns_r_badkey); + + /* Read the time signed and fudge. */ + BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); + cp += INT16SZ; + GETLONG(timesigned, cp); + GETSHORT(fudge, cp); + + /* Read the signature. */ + BOUNDS_CHECK(cp, INT16SZ); + GETSHORT(sigfieldlen, cp); + BOUNDS_CHECK(cp, sigfieldlen); + sigstart = cp; + cp += sigfieldlen; + + /* Skip id and read error. */ + BOUNDS_CHECK(cp, 2*INT16SZ); + cp += INT16SZ; + GETSHORT(error, cp); + + /* Parse the other data. */ + BOUNDS_CHECK(cp, INT16SZ); + GETSHORT(otherfieldlen, cp); + BOUNDS_CHECK(cp, otherfieldlen); + cp += otherfieldlen; + + if (cp != eom) + return (NS_TSIG_ERROR_FORMERR); + + /* + * Do the verification. + */ + + /* Digest the time signed and fudge. */ + cp2 = buf; + PUTSHORT(0, cp2); /*%< Top 16 bits of time. */ + PUTLONG(timesigned, cp2); + PUTSHORT(NS_TSIG_FUDGE, cp2); + + dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, + buf, cp2 - buf, NULL, 0); + + n = dst_verify_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0, + sigstart, sigfieldlen); + if (n < 0) + return (-ns_r_badsig); + + if (sigfieldlen > sizeof(state->sig)) + return (NS_TSIG_ERROR_NO_SPACE); + + memcpy(state->sig, sigstart, sigfieldlen); + state->siglen = sigfieldlen; + + /* Verify the time. */ + if (abs(timesigned - time(NULL)) > fudge) + return (-ns_r_badtime); + + *msglen = recstart - msg; + + if (error != NOERROR) + return (error); + + return (0); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/port/freebsd/include/sys/bitypes.h b/contrib/bind-9.5.2/lib/bind/port/freebsd/include/sys/bitypes.h new file mode 100644 index 0000000000..ef3a6d4832 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/port/freebsd/include/sys/bitypes.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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 __BIT_TYPES_DEFINED__ +#define __BIT_TYPES_DEFINED__ + + /* + * Basic integral types. Omit the typedef if + * not possible for a machine/compiler combination. + */ + typedef /*signed*/ char int8_t; + typedef unsigned char u_int8_t; + typedef short int16_t; + typedef unsigned short u_int16_t; + typedef int int32_t; + typedef unsigned int u_int32_t; + +# if 0 /* don't fight with these unless you need them */ + typedef long long int64_t; + typedef unsigned long long u_int64_t; +# endif + +#endif /* __BIT_TYPES_DEFINED__ */ diff --git a/contrib/bind-9.5.2/lib/bind/port_after.h.in b/contrib/bind-9.5.2/lib/bind/port_after.h.in new file mode 100644 index 0000000000..b7496a2d46 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/port_after.h.in @@ -0,0 +1,526 @@ +/* + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001-2003 Internet Software Consortium. + * + * 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: port_after.h.in,v 1.53.128.7 2008/02/28 05:46:12 marka Exp $ */ + +#ifndef port_after_h +#define port_after_h + +#include +#include +#include +#include +#include +#if (!defined(BSD)) || (BSD < 199306) +#include +#endif +#ifdef HAVE_INTTYPES_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#endif /* HAVE_SYS_SELECT_H */ + +#ifdef REENABLE_SEND +#undef send +#endif + +@NEED_PSELECT@ +@HAVE_SA_LEN@ +@HAVE_MINIMUM_IFREQ@ +@NEED_DAEMON@ +@NEED_STRSEP@ +@NEED_STRERROR@ +#ifdef NEED_STRERROR +const char *isc_strerror(int); +#define strerror isc_strerror +#endif +@HAS_INET6_STRUCTS@ +@HAVE_SIN6_SCOPE_ID@ +@NEED_IN6ADDR_ANY@ +@HAS_IN_ADDR6@ +@HAVE_SOCKADDR_STORAGE@ +@NEED_GETTIMEOFDAY@ +@HAVE_STRNDUP@ +@USE_FIONBIO_IOCTL@ +@INNETGR_ARGS@ +@SETNETGRENT_ARGS@ +@USE_IFNAMELINKID@ +@PORT_NONBLOCK@ + +#ifndef _POSIX_PATH_MAX +#define _POSIX_PATH_MAX 255 +#endif +#ifndef PATH_MAX +#define PATH_MAX _POSIX_PATH_MAX +#endif + +/* + * We need to know the IPv6 address family number even on IPv4-only systems. + * Note that this is NOT a protocol constant, and that if the system has its + * own AF_INET6, different from ours below, all of BIND's libraries and + * executables will need to be recompiled after the system + * has had this type added. The type number below is correct on most BSD- + * derived systems for which AF_INET6 is defined. + */ +#ifndef AF_INET6 +#define AF_INET6 24 +#endif + +#ifndef PF_INET6 +#define PF_INET6 AF_INET6 +#endif + +#ifdef HAS_IN_ADDR6 +/* Map to pre-RFC structure. */ +#define in6_addr in_addr6 +#endif + +#ifndef HAS_INET6_STRUCTS +/* Replace with structure from later rev of O/S if known. */ +struct in6_addr { + u_int8_t s6_addr[16]; +}; + +#define IN6ADDR_ANY_INIT \ + {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }} + +#define IN6ADDR_LOOPBACK_INIT \ + {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }} + +/* Replace with structure from later rev of O/S if known. */ +struct sockaddr_in6 { +#ifdef HAVE_SA_LEN + u_int8_t sin6_len; /* length of this struct */ + u_int8_t sin6_family; /* AF_INET6 */ +#else + u_int16_t sin6_family; /* AF_INET6 */ +#endif + u_int16_t sin6_port; /* transport layer port # */ + u_int32_t sin6_flowinfo; /* IPv6 flow information */ + struct in6_addr sin6_addr; /* IPv6 address */ + u_int32_t sin6_scope_id; /* set of interfaces for a scope */ +}; +#endif /* HAS_INET6_STRUCTS */ + +#ifdef BROKEN_IN6ADDR_INIT_MACROS +#undef IN6ADDR_ANY_INIT +#undef IN6ADDR_LOOPBACK_INIT +#endif + +#ifdef _AIX +#ifndef IN6ADDR_ANY_INIT +#define IN6ADDR_ANY_INIT {{{ 0, 0, 0, 0 }}} +#endif +#ifndef IN6ADDR_LOOPBACK_INIT +#if BYTE_ORDER == BIG_ENDIAN +#define IN6ADDR_LOOPBACK_INIT {{{ 0, 0, 0, 1 }}} +#else +#define IN6ADDR_LOOPBACK_INIT {{{0, 0, 0, 0x01000000}}} +#endif +#endif +#endif + +#ifndef IN6ADDR_ANY_INIT +#ifdef s6_addr +#define IN6ADDR_ANY_INIT \ + {{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}} +#else +#define IN6ADDR_ANY_INIT \ + {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }} +#endif + +#endif +#ifndef IN6ADDR_LOOPBACK_INIT +#ifdef s6_addr +#define IN6ADDR_LOOPBACK_INIT \ + {{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}} +#else +#define IN6ADDR_LOOPBACK_INIT \ + {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }} +#endif +#endif + +#ifndef HAVE_SOCKADDR_STORAGE +#define __SS_MAXSIZE 128 +#define __SS_ALLIGSIZE (sizeof (long)) + +struct sockaddr_storage { +#ifdef HAVE_SA_LEN + u_int8_t ss_len; /* address length */ + u_int8_t ss_family; /* address family */ + char __ss_pad1[__SS_ALLIGSIZE - 2 * sizeof(u_int8_t)]; + long __ss_align; + char __ss_pad2[__SS_MAXSIZE - 2 * __SS_ALLIGSIZE]; +#else + u_int16_t ss_family; /* address family */ + char __ss_pad1[__SS_ALLIGSIZE - sizeof(u_int16_t)]; + long __ss_align; + char __ss_pad2[__SS_MAXSIZE - 2 * __SS_ALLIGSIZE]; +#endif +}; +#endif + + +#if !defined(HAS_INET6_STRUCTS) || defined(NEED_IN6ADDR_ANY) +#define in6addr_any isc_in6addr_any +extern const struct in6_addr in6addr_any; +#endif + +/* + * IN6_ARE_ADDR_EQUAL, IN6_IS_ADDR_UNSPECIFIED, IN6_IS_ADDR_V4COMPAT and + * IN6_IS_ADDR_V4MAPPED are broken in glibc 2.1. + */ +#ifdef __GLIBC__ +#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2) +#undef IN6_ARE_ADDR_EQUAL +#undef IN6_IS_ADDR_UNSPECIFIED +#undef IN6_IS_ADDR_V4COMPAT +#undef IN6_IS_ADDR_V4MAPPED +#endif +#endif + +#ifndef IN6_ARE_ADDR_EQUAL +#define IN6_ARE_ADDR_EQUAL(a,b) \ + (memcmp(&(a)->s6_addr[0], &(b)->s6_addr[0], sizeof(struct in6_addr)) == 0) +#endif + +#ifndef IN6_IS_ADDR_UNSPECIFIED +#define IN6_IS_ADDR_UNSPECIFIED(a) \ + IN6_ARE_ADDR_EQUAL(a, &in6addr_any) +#endif + +#ifndef IN6_IS_ADDR_LOOPBACK +extern const struct in6_addr isc_in6addr_loopback; +#define IN6_IS_ADDR_LOOPBACK(a) \ + IN6_ARE_ADDR_EQUAL(a, &isc_in6addr_loopback) +#endif + +#ifndef IN6_IS_ADDR_V4MAPPED +#define IN6_IS_ADDR_V4MAPPED(a) \ + ((a)->s6_addr[0] == 0x00 && (a)->s6_addr[1] == 0x00 && \ + (a)->s6_addr[2] == 0x00 && (a)->s6_addr[3] == 0x00 && \ + (a)->s6_addr[4] == 0x00 && (a)->s6_addr[5] == 0x00 && \ + (a)->s6_addr[6] == 0x00 && (a)->s6_addr[9] == 0x00 && \ + (a)->s6_addr[8] == 0x00 && (a)->s6_addr[9] == 0x00 && \ + (a)->s6_addr[10] == 0xff && (a)->s6_addr[11] == 0xff) +#endif + +#ifndef IN6_IS_ADDR_SITELOCAL +#define IN6_IS_ADDR_SITELOCAL(a) \ + (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0xc0)) +#endif + +#ifndef IN6_IS_ADDR_LINKLOCAL +#define IN6_IS_ADDR_LINKLOCAL(a) \ + (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0x80)) +#endif + +#ifndef IN6_IS_ADDR_MULTICAST +#define IN6_IS_ADDR_MULTICAST(a) ((a)->s6_addr[0] == 0xff) +#endif + +#ifndef __IPV6_ADDR_MC_SCOPE +#define __IPV6_ADDR_MC_SCOPE(a) ((a)->s6_addr[1] & 0x0f) +#endif + +#ifndef __IPV6_ADDR_SCOPE_SITELOCAL +#define __IPV6_ADDR_SCOPE_SITELOCAL 0x05 +#endif +#ifndef __IPV6_ADDR_SCOPE_ORGLOCAL +#define __IPV6_ADDR_SCOPE_ORGLOCAL 0x08 +#endif + +#ifndef IN6_IS_ADDR_MC_SITELOCAL +#define IN6_IS_ADDR_MC_SITELOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) && \ + (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_SITELOCAL)) +#endif + +#ifndef IN6_IS_ADDR_MC_ORGLOCAL +#define IN6_IS_ADDR_MC_ORGLOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) && \ + (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_ORGLOCAL)) +#endif + +#ifndef INADDR_NONE +#define INADDR_NONE 0xffffffff +#endif + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 256 +#endif + +#ifndef INET6_ADDRSTRLEN +/* sizeof("aaaa:bbbb:cccc:dddd:eeee:ffff:123.123.123.123") */ +#define INET6_ADDRSTRLEN 46 +#endif + +#ifndef MIN +#define MIN(x,y) (((x) <= (y)) ? (x) : (y)) +#endif + +#ifndef MAX +#define MAX(x,y) (((x) >= (y)) ? (x) : (y)) +#endif + +#ifdef NEED_DAEMON +int daemon(int nochdir, int noclose); +#endif + +#ifdef NEED_STRSEP +char * strsep(char **stringp, const char *delim); +#endif + +#ifndef ALIGN +#define ALIGN(p) (((uintptr_t)(p) + (sizeof(long) - 1)) & ~(sizeof(long) - 1)) +#endif + +#ifdef NEED_SETGROUPENT +int setgroupent(int stayopen); +#endif + +#ifdef NEED_GETGROUPLIST +int getgrouplist(GETGROUPLIST_ARGS); +#endif + +#ifdef POSIX_GETGRNAM_R +int +__posix_getgrnam_r(const char *, struct group *, char *, int, struct group **); +#endif + +#ifdef NEED_GETGRNAM_R +int +getgrnam_r(const char *, struct group *, char *, size_t, struct group **); +#endif + +#ifdef POSIX_GETGRGID_R +int +__posix_getgrgid_r(gid_t, struct group *, char *, int, struct group **) ; +#endif + +#ifdef NEED_GETGRGID_R +int +getgrgid_r(gid_t, struct group *, char *, size_t, struct group **); +#endif + +#ifdef NEED_GETGRENT_R +GROUP_R_RETURN getgrent_r(struct group *gptr, GROUP_R_ARGS); +#endif + +#ifdef NEED_SETGRENT_R +GROUP_R_SET_RETURN setgrent_r(GROUP_R_ENT_ARGS); +#endif + +#ifdef NEED_ENDGRENT_R +GROUP_R_END_RETURN endgrent_r(GROUP_R_ENT_ARGS); +#endif + +#if defined(NEED_INNETGR_R) && defined(NGR_R_RETURN) +NGR_R_RETURN +innetgr_r(const char *, const char *, const char *, const char *); +#endif + +#ifdef NEED_SETNETGRENT_R +#ifdef NGR_R_SET_ARGS +NGR_R_SET_RETURN setnetgrent_r(NGR_R_SET_CONST char *netgroup, NGR_R_SET_ARGS); +#else +NGR_R_SET_RETURN setnetgrent_r(NGR_R_SET_CONST char *netgroup); +#endif +#endif + +#ifdef NEED_ENDNETGRENT_R +#ifdef NGR_R_END_ARGS +NGR_R_END_RETURN endnetgrent_r(NGR_R_END_ARGS); +#else +NGR_R_END_RETURN endnetgrent_r(void); +#endif +#endif + +#ifdef POSIX_GETPWNAM_R +int +__posix_getpwnam_r(const char *login, struct passwd *pwptr, + char *buf, size_t buflen, struct passwd **result); +#endif + +#ifdef NEED_GETPWNAM_R +int +getpwnam_r(const char *login, struct passwd *pwptr, + char *buf, size_t buflen, struct passwd **result); +#endif + +#ifdef POSIX_GETPWUID_R +int +__posix_getpwuid_r(uid_t uid, struct passwd *pwptr, + char *buf, int buflen, struct passwd **result); +#endif + +#ifdef NEED_GETPWUID_R +int +getpwuid_r(uid_t uid, struct passwd *pwptr, + char *buf, size_t buflen, struct passwd **result); +#endif + +#ifdef NEED_SETPWENT_R +#ifdef PASS_R_ENT_ARGS +PASS_R_SET_RETURN setpwent_r(PASS_R_ENT_ARGS); +#else +PASS_R_SET_RETURN setpwent_r(void); +#endif + +#endif + +#ifdef NEED_SETPASSENT_R +#ifdef PASS_R_ENT_ARGS +PASS_R_SET_RETURN setpassent_r(int stayopen, PASS_R_ENT_ARGS); +#else +PASS_R_SET_RETURN setpassent_r(int stayopen); +#endif +#endif + +#ifdef NEED_GETPWENT_R +PASS_R_RETURN getpwent_r(struct passwd *pwptr, PASS_R_ARGS); +#endif + +#ifdef NEED_ENDPWENT_R +void endpwent_r(void); +#endif + +#ifdef NEED_SETPASSENT +int setpassent(int stayopen); +#endif + +#define gettimeofday isc__gettimeofday +#ifdef NEED_GETTIMEOFDAY +int isc__gettimeofday(struct timeval *tvp, struct _TIMEZONE *tzp); +#else +int isc__gettimeofday(struct timeval *tp, struct timezone *tzp); +#endif + +int getnetgrent(NGR_R_CONST char **machinep, NGR_R_CONST char **userp, + NGR_R_CONST char **domainp); + +#ifdef NGR_R_ARGS +int getnetgrent_r(NGR_R_CONST char **machinep, NGR_R_CONST char **userp, + NGR_R_CONST char **domainp, NGR_R_ARGS); +#endif + +#ifdef SETNETGRENT_ARGS +void setnetgrent(SETNETGRENT_ARGS); +#else +void setnetgrent(const char *netgroup); +#endif + +void endnetgrent(void); + +#ifdef INNETGR_ARGS +int innetgr(INNETGR_ARGS); +#else +int innetgr(const char *netgroup, const char *machine, + const char *user, const char *domain); +#endif + +#ifdef NGR_R_SET_ARGS +NGR_R_SET_RETURN +setnetgrent_r(NGR_R_SET_CONST char *netgroup, NGR_R_SET_ARGS); +#else +NGR_R_SET_RETURN +setnetgrent_r(NGR_R_SET_CONST char *netgroup); +#endif + +#ifdef NEED_STRTOUL +unsigned long strtoul(const char *, char **, int); +#endif + +#ifdef NEED_SUN4PROTOS +#include +#ifndef __SIZE_TYPE__ +#define __SIZE_TYPE__ int +#endif +struct sockaddr; +struct iovec; +struct timeval; +struct timezone; +int fprintf(FILE *, const char *, ...); +int getsockname(int, struct sockaddr *, int *); +int getpeername(int, struct sockaddr *, int *); +int socket(int, int, int); +int connect(int, const struct sockaddr *, int); +int writev(int, struct iovec *, int); +int readv(int, struct iovec *, int); +int send(int, const char *, int, int); +void bzero(char *, int); +int recvfrom(int, char *, int, int, struct sockaddr *, int *); +int syslog(int, const char *, ... ); +int printf(const char *, ...); +__SIZE_TYPE__ fread(void *, __SIZE_TYPE__, __SIZE_TYPE__, FILE *); +__SIZE_TYPE__ fwrite(const void *, __SIZE_TYPE__, __SIZE_TYPE__, FILE *); +int fclose(FILE *); +int ungetc(int, FILE *); +int scanf(const char *, ...); +int sscanf(const char *, const char *, ... ); +int tolower(int); +int toupper(int); +int strcasecmp(const char *, const char *); +int strncasecmp(const char *, const char *, int); +int select(int, fd_set *, fd_set *, fd_set *, struct timeval *); +#ifdef gettimeofday +#undef gettimeofday +int gettimeofday(struct timeval *, struct timezone *); +#define gettimeofday isc__gettimeofday +#else +int gettimeofday(struct timeval *, struct timezone *); +#endif +long strtol(const char*, char **, int); +int fseek(FILE *, long, int); +int setsockopt(int, int, int, const char *, int); +int bind(int, const struct sockaddr *, int); +void bcopy(char *, char *, int); +int fputc(char, FILE *); +int listen(int, int); +int accept(int, struct sockaddr *, int *); +int getsockopt(int, int, int, char *, int *); +int vfprintf(FILE *, const char *, va_list); +int fflush(FILE *); +int fgetc(FILE *); +int fputs(const char *, FILE *); +int fchown(int, int, int); +void setbuf(FILE *, char *); +int gethostname(char *, int); +int rename(const char *, const char *); +time_t time(time_t *); +int fscanf(FILE *, const char *, ...); +int sscanf(const char *, const char *, ...); +int ioctl(int, int, caddr_t); +void perror(const char *); + +#if !defined(__USE_FIXED_PROTOTYPES__) && !defined(__cplusplus) && !defined(__STRICT_ANSI__) +/* + * 'gcc -ansi' changes the prototype for vsprintf(). + * Use this prototype when 'gcc -ansi' is not in effect. + */ +char *vsprintf(char *, const char *, va_list); +#endif +#endif + +#endif diff --git a/contrib/bind-9.5.2/lib/bind/port_before.h.in b/contrib/bind-9.5.2/lib/bind/port_before.h.in new file mode 100644 index 0000000000..4910091221 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/port_before.h.in @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2005-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001 Internet Software Consortium. + * + * 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: port_before.h.in,v 1.27.128.3 2008/02/28 05:46:12 marka Exp $ */ + +#ifndef port_before_h +#define port_before_h +#include + +#ifdef NEED_SUN4PROTOS +#define _PARAMS(x) x +#endif + +struct group; /* silence warning */ +struct passwd; /* silence warning */ +struct timeval; /* silence warning */ +struct timezone; /* silence warning */ + +#ifdef HAVE_SYS_TIMERS_H +#include +#endif +#include + +#ifdef ISC_PLATFORM_NEEDTIMESPEC +#include /* For time_t */ +struct timespec { + time_t tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ +}; +#endif +#ifndef HAVE_MEMMOVE +#define memmove(a,b,c) bcopy(b,a,c) +#endif + +@WANT_IRS_GR@ +@WANT_IRS_NIS@ +@WANT_IRS_PW@ + +@BSD_COMP@ +@USE_POLL@ +@HAVE_MD5@ +@SOLARIS2@ + +@DO_PTHREADS@ +@GETGROUPLIST_ARGS@ +@GETNETBYADDR_ADDR_T@ +@SETPWENT_VOID@ +@SETGRENT_VOID@ + +@NET_R_ARGS@ +@NET_R_BAD@ +@NET_R_COPY@ +@NET_R_COPY_ARGS@ +@NET_R_END_RESULT@ +@NET_R_END_RETURN@ +@NET_R_ENT_ARGS@ +@NET_R_OK@ +@NET_R_RETURN@ +@NET_R_SET_RESULT@ +@NET_R_SETANSWER@ +@NET_R_SET_RETURN@ +@NETENT_DATA@ + +@GROUP_R_RETURN@ +@GROUP_R_SET_RETURN@ +@GROUP_R_SET_RESULT@ +@GROUP_R_END_RETURN@ +@GROUP_R_END_RESULT@ +@GROUP_R_ARGS@ +@GROUP_R_ENT_ARGS@ +@GROUP_R_OK@ +@GROUP_R_BAD@ + +@HOST_R_ARGS@ +@HOST_R_BAD@ +@HOST_R_COPY@ +@HOST_R_COPY_ARGS@ +@HOST_R_END_RESULT@ +@HOST_R_END_RETURN@ +@HOST_R_ENT_ARGS@ +@HOST_R_ERRNO@ +@HOST_R_OK@ +@HOST_R_RETURN@ +@HOST_R_SETANSWER@ +@HOST_R_SET_RESULT@ +@HOST_R_SET_RETURN@ +@HOSTENT_DATA@ + +@NGR_R_ARGS@ +@NGR_R_BAD@ +@NGR_R_COPY@ +@NGR_R_COPY_ARGS@ +@NGR_R_CONST@ +@NGR_R_END_RESULT@ +@NGR_R_END_RETURN@ +@NGR_R_END_ARGS@ +@NGR_R_OK@ +@NGR_R_RETURN@ +@NGR_R_SET_CONST@ +@NGR_R_SET_RESULT@ +@NGR_R_SET_RETURN@ +@NGR_R_SET_ARGS@ +@NGR_R_PRIVATE@ + +#if !defined(NGR_R_SET_ARGS) && defined(NGR_R_END_ARGS) +#define NGR_R_SET_ARGS NGR_R_END_ARGS +#endif + +@PROTO_R_ARGS@ +@PROTO_R_BAD@ +@PROTO_R_COPY@ +@PROTO_R_COPY_ARGS@ +@PROTO_R_END_RESULT@ +@PROTO_R_END_RETURN@ +@PROTO_R_ENT_ARGS@ +@PROTO_R_ENT_UNUSED@ +@PROTO_R_OK@ +@PROTO_R_SETANSWER@ +@PROTO_R_RETURN@ +@PROTO_R_SET_RESULT@ +@PROTO_R_SET_RETURN@ +@PROTOENT_DATA@ + +@PASS_R_ARGS@ +@PASS_R_BAD@ +@PASS_R_COPY@ +@PASS_R_COPY_ARGS@ +@PASS_R_END_RESULT@ +@PASS_R_END_RETURN@ +@PASS_R_ENT_ARGS@ +@PASS_R_OK@ +@PASS_R_RETURN@ +@PASS_R_SET_RESULT@ +@PASS_R_SET_RETURN@ + +@SERV_R_ARGS@ +@SERV_R_BAD@ +@SERV_R_COPY@ +@SERV_R_COPY_ARGS@ +@SERV_R_END_RESULT@ +@SERV_R_END_RETURN@ +@SERV_R_ENT_ARGS@ +@SERV_R_ENT_UNUSED@ +@SERV_R_OK@ +@SERV_R_SETANSWER@ +@SERV_R_RETURN@ +@SERV_R_SET_RESULT@ +@SERV_R_SET_RETURN@ +@SERVENT_DATA@ + + +#define DE_CONST(konst, var) \ + do { \ + union { const void *k; void *v; } _u; \ + _u.k = konst; \ + var = _u.v; \ + } while (0) + +#define UNUSED(x) (x) = (x) + +@SOLARIS_BITTYPES@ +@ISC_SOCKLEN_T@ + +#ifdef __GNUC__ +#define ISC_FORMAT_PRINTF(fmt, args) \ + __attribute__((__format__(__printf__, fmt, args))) +#else +#define ISC_FORMAT_PRINTF(fmt, args) +#endif + +/* Pull in host order macros when _XOPEN_SOURCE_EXTENDED is defined. */ +#if defined(__hpux) && defined(_XOPEN_SOURCE_EXTENDED) +#include +#endif + +#endif + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/resolv/herror.c b/contrib/bind-9.5.2/lib/bind/resolv/herror.c new file mode 100644 index 0000000000..703ab8fe4d --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/resolv/herror.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 1987, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)herror.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: herror.c,v 1.4 2005/04/27 04:56:41 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include "port_before.h" + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "port_after.h" + +const char *h_errlist[] = { + "Resolver Error 0 (no error)", + "Unknown host", /*%< 1 HOST_NOT_FOUND */ + "Host name lookup failure", /*%< 2 TRY_AGAIN */ + "Unknown server error", /*%< 3 NO_RECOVERY */ + "No address associated with name", /*%< 4 NO_ADDRESS */ +}; +int h_nerr = { sizeof h_errlist / sizeof h_errlist[0] }; + +#if !(__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) +#undef h_errno +int h_errno; +#endif + +/*% + * herror -- + * print the error indicated by the h_errno value. + */ +void +herror(const char *s) { + struct iovec iov[4], *v = iov; + char *t; + + if (s != NULL && *s != '\0') { + DE_CONST(s, t); + v->iov_base = t; + v->iov_len = strlen(t); + v++; + DE_CONST(": ", t); + v->iov_base = t; + v->iov_len = 2; + v++; + } + DE_CONST(hstrerror(*__h_errno()), t); + v->iov_base = t; + v->iov_len = strlen(v->iov_base); + v++; + DE_CONST("\n", t); + v->iov_base = t; + v->iov_len = 1; + writev(STDERR_FILENO, iov, (v - iov) + 1); +} + +/*% + * hstrerror -- + * return the string associated with a given "host" errno value. + */ +const char * +hstrerror(int err) { + if (err < 0) + return ("Resolver internal error"); + else if (err < h_nerr) + return (h_errlist[err]); + return ("Unknown resolver error"); +} + +/*! \file */ diff --git a/contrib/bind-9.5.2/lib/bind/resolv/mtctxres.c b/contrib/bind-9.5.2/lib/bind/resolv/mtctxres.c new file mode 100644 index 0000000000..635bbd4400 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/resolv/mtctxres.c @@ -0,0 +1,129 @@ +#include +#ifdef DO_PTHREADS +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#ifdef DO_PTHREADS +static pthread_key_t key; +static int mt_key_initialized = 0; + +static int __res_init_ctx(void); +static void __res_destroy_ctx(void *); + +#if defined(sun) && !defined(__GNUC__) +#pragma init (_mtctxres_init) +#endif +#endif + +static mtctxres_t sharedctx; + +#ifdef DO_PTHREADS +/* + * Initialize the TSD key. By doing this at library load time, we're + * implicitly running without interference from other threads, so there's + * no need for locking. + */ +static void +_mtctxres_init(void) { + int pthread_keycreate_ret; + + pthread_keycreate_ret = pthread_key_create(&key, __res_destroy_ctx); + if (pthread_keycreate_ret == 0) + mt_key_initialized = 1; +} +#endif + +/* + * To support binaries that used the private MT-safe interface in + * Solaris 8, we still need to provide the __res_enable_mt() + * and __res_disable_mt() entry points. They're do-nothing routines. + */ +int +__res_enable_mt(void) { + return (-1); +} + +int +__res_disable_mt(void) { + return (0); +} + +#ifdef DO_PTHREADS +static int +__res_init_ctx(void) { + + mtctxres_t *mt; + int ret; + + + if (pthread_getspecific(key) != 0) { + /* Already exists */ + return (0); + } + + if ((mt = malloc(sizeof (mtctxres_t))) == 0) { + errno = ENOMEM; + return (-1); + } + + memset(mt, 0, sizeof (mtctxres_t)); + + if ((ret = pthread_setspecific(key, mt)) != 0) { + free(mt); + errno = ret; + return (-1); + } + + return (0); +} + +static void +__res_destroy_ctx(void *value) { + + mtctxres_t *mt = (mtctxres_t *)value; + + if (mt != 0) + free(mt); +} +#endif + +mtctxres_t * +___mtctxres(void) { +#ifdef DO_PTHREADS + mtctxres_t *mt; + + /* + * This if clause should only be executed if we are linking + * statically. When linked dynamically _mtctxres_init() should + * be called at binding time due the #pragma above. + */ + if (!mt_key_initialized) { + static pthread_mutex_t keylock = PTHREAD_MUTEX_INITIALIZER; + if (pthread_mutex_lock(&keylock) == 0) { + _mtctxres_init(); + (void) pthread_mutex_unlock(&keylock); + } + } + + /* + * If we have already been called in this thread return the existing + * context. Otherwise recreat a new context and return it. If + * that fails return a global context. + */ + if (mt_key_initialized) { + if (((mt = pthread_getspecific(key)) != 0) || + (__res_init_ctx() == 0 && + (mt = pthread_getspecific(key)) != 0)) { + return (mt); + } + } +#endif + return (&sharedctx); +} diff --git a/contrib/bind-9.5.2/lib/bind/resolv/res_comp.c b/contrib/bind-9.5.2/lib/bind/resolv/res_comp.c new file mode 100644 index 0000000000..08a66b21c5 --- /dev/null +++ b/contrib/bind-9.5.2/lib/bind/resolv/res_comp.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 1985, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION 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. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: res_comp.c,v 1.5 2005/07/28 06:51:50 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include "port_before.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "port_after.h" + +/*% + * Expand compressed domain name 'src' to full domain name. + * + * \li 'msg' is a pointer to the begining of the message, + * \li 'eom' points to the first location after the message, + * \li 'dst' is a pointer to a buffer of size 'dstsiz' for the result. + * \li Return size of compressed name or -1 if there was an error. + */ +int +dn_expand(const u_char *msg, const u_char *eom, const u_char *src, + char *dst, int dstsiz) +{ + int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz); + + if (n > 0 && dst[0] == '.') + dst[0] = '\0'; + return (n); +} + +/*% + * Pack domain name 'exp_dn' in presentation form into 'comp_dn'. + * + * \li Return the size of the compressed name or -1. + * \li 'length' is the size of the array pointed to by 'comp_dn'. + */ +int +dn_comp(const char *src, u_char *dst, int dstsiz, + u_char **dnptrs, u_char **lastdnptr) +{ + return (ns_name_compress(src, dst, (size_t)dstsiz, + (const u_char **)dnptrs, + (const u_char **)lastdnptr)); +} + +/*% + * Skip over a compressed domain name. Return the size or -1. + */ +int +dn_skipname(const u_char *ptr, const u_char *eom) { + const u_char *saveptr = ptr; + + if (ns_name_skip(&ptr, eom) == -1) + return (-1); + return (ptr - saveptr); +} + +/*% + * Verify that a domain name uses an acceptable character set. + * + * Note the conspicuous absence of ctype macros in these definitions. On + * non-ASCII hosts, we can't depend on string literals or ctype macros to + * tell us anything about network-format data. The rest of the BIND system + * is not careful about this, but for some reason, we're doing it right here. + */ +#define PERIOD 0x2e +#define hyphenchar(c) ((c) == 0x2d) +#define bslashchar(c) ((c) == 0x5c) +#define periodchar(c) ((c) == PERIOD) +#define asterchar(c) ((c) == 0x2a) +#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \ + || ((c) >= 0x61 && (c) <= 0x7a)) +#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39) + +#define borderchar(c) (alphachar(c) || digitchar(c)) +#define middlechar(c) (borderchar(c) || hyphenchar(c)) +#define domainchar(c) ((c) > 0x20 && (c) < 0x7f) + +int +res_hnok(const char *dn) { + int pch = PERIOD, ch = *dn++; + + while (ch != '\0') { + int nch = *dn++; + + if (periodchar(ch)) { + (void)NULL; + } else if (periodchar(pch)) { + if (!borderchar(ch)) + return (0); + } else if (periodchar(nch) || nch == '\0') { + if (!borderchar(ch)) + return (0); + } else { + if (!middlechar(ch)) + return (0); + } + pch = ch, ch = nch; + } + return (1); +} + +/*% + * hostname-like (A, MX, WKS) owners can have "*" as their first label + * but must otherwise be as a host name. + */ +int +res_ownok(const char *dn) { + if (asterchar(dn[0])) { + if (periodchar(dn[1])) + return (res_hnok(dn+2)); + if (dn[1] == '\0') + return (1); + } + return (res_hnok(dn)); +} + +/*% + * SOA RNAMEs and RP RNAMEs can have any printable character in their first + * label, but the rest of the name has to look like a host name. + */ +int +res_mailok(const char *dn) { + int ch, escaped = 0; + + /* "." is a valid missing representation */ + if (*dn == '\0') + return (1); + + /* otherwise