From 15eb2ac32214256015b9a5d05fbd8c857318f179 Mon Sep 17 00:00:00 2001 From: Jeroen Ruigrok/asmodai Date: Mon, 20 Sep 2004 06:33:19 +0000 Subject: [PATCH] Add BIND 9.2.4rc7. Notable changes: 1643. [bug] dns_db_closeversion() could leak memory / node references. [RT #11163] 1650. [bug] dig, nslookup: flush standard out after each command. 1654. [bug] isc_result_totext() contained array bounds read error. 1681. [bug] Only set SO_REUSEADDR when a port is specified in isc_socket_bind(). [RT #11742] 1686. [bug] Named sent a extraneous NOTIFY when it received a redundant UPDATE request. [RT #11943] 1687. [bug] Race condition in dispatch. [RT #10272] 1690. [bug] Delay detaching view from the client until UPDATE processing completes when shutting down. [RT #11714] --- contrib/bind-9.2.4rc7/CHANGES | 4679 +++++++++++++ contrib/bind-9.2.4rc7/COPYRIGHT | 30 + contrib/bind-9.2.4rc7/FAQ | 449 ++ contrib/bind-9.2.4rc7/Makefile.in | 59 + contrib/bind-9.2.4rc7/README | 351 + contrib/bind-9.2.4rc7/README.DELETED | 48 + contrib/bind-9.2.4rc7/README.DRAGONFLY | 53 + contrib/bind-9.2.4rc7/acconfig.h | 132 + contrib/bind-9.2.4rc7/bin/check/check-tool.c | 52 + contrib/bind-9.2.4rc7/bin/check/check-tool.h | 34 + .../bind-9.2.4rc7/bin/check/named-checkconf.8 | 52 + .../bind-9.2.4rc7/bin/check/named-checkconf.c | 138 + .../bin/check/named-checkconf.html | 196 + .../bind-9.2.4rc7/bin/check/named-checkzone.8 | 65 + .../bind-9.2.4rc7/bin/check/named-checkzone.c | 178 + .../bin/check/named-checkzone.html | 237 + contrib/bind-9.2.4rc7/bin/dig/dig.1 | 370 + contrib/bind-9.2.4rc7/bin/dig/dig.c | 1409 ++++ contrib/bind-9.2.4rc7/bin/dig/dig.html | 1158 ++++ contrib/bind-9.2.4rc7/bin/dig/dighost.c | 2723 ++++++++ contrib/bind-9.2.4rc7/bin/dig/host.1 | 130 + contrib/bind-9.2.4rc7/bin/dig/host.c | 728 ++ contrib/bind-9.2.4rc7/bin/dig/host.html | 443 ++ .../bind-9.2.4rc7/bin/dig/include/dig/dig.h | 280 + contrib/bind-9.2.4rc7/bin/dig/nslookup.c | 882 +++ .../bind-9.2.4rc7/bin/dnssec/dnssec-keygen.8 | 168 + .../bind-9.2.4rc7/bin/dnssec/dnssec-keygen.c | 402 ++ .../bin/dnssec/dnssec-keygen.html | 575 ++ .../bin/dnssec/dnssec-makekeyset.8 | 113 + .../bin/dnssec/dnssec-makekeyset.c | 466 ++ .../bin/dnssec/dnssec-makekeyset.html | 407 ++ .../bind-9.2.4rc7/bin/dnssec/dnssec-signkey.8 | 108 + .../bind-9.2.4rc7/bin/dnssec/dnssec-signkey.c | 471 ++ .../bin/dnssec/dnssec-signkey.html | 407 ++ .../bin/dnssec/dnssec-signzone.8 | 155 + .../bin/dnssec/dnssec-signzone.c | 1880 +++++ .../bin/dnssec/dnssec-signzone.html | 556 ++ contrib/bind-9.2.4rc7/bin/dnssec/dnssectool.c | 260 + contrib/bind-9.2.4rc7/bin/dnssec/dnssectool.h | 73 + contrib/bind-9.2.4rc7/bin/named/aclconf.c | 231 + contrib/bind-9.2.4rc7/bin/named/client.c | 2215 ++++++ contrib/bind-9.2.4rc7/bin/named/config.c | 455 ++ contrib/bind-9.2.4rc7/bin/named/control.c | 126 + contrib/bind-9.2.4rc7/bin/named/controlconf.c | 1329 ++++ .../bin/named/include/named/aclconf.h | 72 + .../bin/named/include/named/client.h | 311 + .../bin/named/include/named/config.h | 68 + .../bin/named/include/named/control.h | 82 + .../bin/named/include/named/globals.h | 113 + .../bin/named/include/named/interfacemgr.h | 153 + .../bin/named/include/named/listenlist.h | 104 + .../bin/named/include/named/log.h | 95 + .../bin/named/include/named/logconf.h | 32 + .../bin/named/include/named/lwaddr.h | 34 + .../bin/named/include/named/lwdclient.h | 230 + .../bin/named/include/named/lwresd.h | 111 + .../bin/named/include/named/lwsearch.h | 110 + .../bin/named/include/named/main.h | 29 + .../bin/named/include/named/notify.h | 54 + .../bin/named/include/named/query.h | 87 + .../bin/named/include/named/server.h | 182 + .../bin/named/include/named/sortlist.h | 84 + .../bin/named/include/named/tkeyconf.h | 51 + .../bin/named/include/named/tsigconf.h | 47 + .../bin/named/include/named/types.h | 41 + .../bin/named/include/named/update.h | 49 + .../bin/named/include/named/xfrout.h | 38 + .../bin/named/include/named/zoneconf.h | 61 + .../bind-9.2.4rc7/bin/named/interfacemgr.c | 738 ++ contrib/bind-9.2.4rc7/bin/named/listenlist.c | 136 + contrib/bind-9.2.4rc7/bin/named/log.c | 203 + contrib/bind-9.2.4rc7/bin/named/logconf.c | 295 + contrib/bind-9.2.4rc7/bin/named/lwaddr.c | 92 + contrib/bind-9.2.4rc7/bin/named/lwdclient.c | 450 ++ contrib/bind-9.2.4rc7/bin/named/lwderror.c | 78 + contrib/bind-9.2.4rc7/bin/named/lwdgabn.c | 655 ++ contrib/bind-9.2.4rc7/bin/named/lwdgnba.c | 274 + contrib/bind-9.2.4rc7/bin/named/lwdgrbn.c | 513 ++ contrib/bind-9.2.4rc7/bin/named/lwdnoop.c | 86 + contrib/bind-9.2.4rc7/bin/named/lwresd.8 | 140 + contrib/bind-9.2.4rc7/bin/named/lwresd.c | 855 +++ contrib/bind-9.2.4rc7/bin/named/lwresd.html | 541 ++ contrib/bind-9.2.4rc7/bin/named/lwsearch.c | 199 + contrib/bind-9.2.4rc7/bin/named/main.c | 656 ++ contrib/bind-9.2.4rc7/bin/named/named.8 | 167 + contrib/bind-9.2.4rc7/bin/named/named.html | 633 ++ contrib/bind-9.2.4rc7/bin/named/notify.c | 151 + contrib/bind-9.2.4rc7/bin/named/query.c | 3899 +++++++++++ contrib/bind-9.2.4rc7/bin/named/server.c | 3132 +++++++++ contrib/bind-9.2.4rc7/bin/named/sortlist.c | 144 + contrib/bind-9.2.4rc7/bin/named/tkeyconf.c | 117 + contrib/bind-9.2.4rc7/bin/named/tsigconf.c | 170 + .../bin/named/unix/include/named/os.h | 58 + contrib/bind-9.2.4rc7/bin/named/unix/os.c | 569 ++ contrib/bind-9.2.4rc7/bin/named/update.c | 2634 +++++++ contrib/bind-9.2.4rc7/bin/named/xfrout.c | 1709 +++++ contrib/bind-9.2.4rc7/bin/named/zoneconf.c | 613 ++ contrib/bind-9.2.4rc7/bin/nsupdate/nsupdate.8 | 347 + contrib/bind-9.2.4rc7/bin/nsupdate/nsupdate.c | 1974 ++++++ .../bind-9.2.4rc7/bin/nsupdate/nsupdate.html | 984 +++ .../bind-9.2.4rc7/bin/rndc/include/rndc/os.h | 44 + contrib/bind-9.2.4rc7/bin/rndc/rndc-confgen.8 | 130 + contrib/bind-9.2.4rc7/bin/rndc/rndc-confgen.c | 322 + .../bind-9.2.4rc7/bin/rndc/rndc-confgen.html | 548 ++ contrib/bind-9.2.4rc7/bin/rndc/rndc.8 | 118 + contrib/bind-9.2.4rc7/bin/rndc/rndc.c | 715 ++ contrib/bind-9.2.4rc7/bin/rndc/rndc.conf | 36 + contrib/bind-9.2.4rc7/bin/rndc/rndc.conf.5 | 142 + contrib/bind-9.2.4rc7/bin/rndc/rndc.conf.html | 381 + contrib/bind-9.2.4rc7/bin/rndc/rndc.html | 424 ++ contrib/bind-9.2.4rc7/bin/rndc/unix/os.c | 68 + contrib/bind-9.2.4rc7/bin/rndc/util.c | 55 + contrib/bind-9.2.4rc7/bin/rndc/util.h | 49 + contrib/bind-9.2.4rc7/lib/bind/README | 4 + contrib/bind-9.2.4rc7/lib/bind/api | 3 + contrib/bind-9.2.4rc7/lib/bind/bsd/daemon.c | 79 + .../bind-9.2.4rc7/lib/bind/bsd/ftruncate.c | 63 + .../bind-9.2.4rc7/lib/bind/bsd/gettimeofday.c | 62 + contrib/bind-9.2.4rc7/lib/bind/bsd/mktemp.c | 154 + contrib/bind-9.2.4rc7/lib/bind/bsd/putenv.c | 25 + contrib/bind-9.2.4rc7/lib/bind/bsd/readv.c | 38 + contrib/bind-9.2.4rc7/lib/bind/bsd/setenv.c | 149 + .../bind-9.2.4rc7/lib/bind/bsd/setitimer.c | 27 + .../bind-9.2.4rc7/lib/bind/bsd/strcasecmp.c | 122 + contrib/bind-9.2.4rc7/lib/bind/bsd/strdup.c | 18 + contrib/bind-9.2.4rc7/lib/bind/bsd/strerror.c | 90 + contrib/bind-9.2.4rc7/lib/bind/bsd/strpbrk.c | 68 + contrib/bind-9.2.4rc7/lib/bind/bsd/strsep.c | 86 + contrib/bind-9.2.4rc7/lib/bind/bsd/strtoul.c | 117 + contrib/bind-9.2.4rc7/lib/bind/bsd/utimes.c | 39 + contrib/bind-9.2.4rc7/lib/bind/bsd/writev.c | 87 + contrib/bind-9.2.4rc7/lib/bind/config.h.in | 45 + contrib/bind-9.2.4rc7/lib/bind/dst/dst_api.c | 1048 +++ .../bind-9.2.4rc7/lib/bind/dst/dst_internal.h | 154 + .../bind-9.2.4rc7/lib/bind/dst/hmac_link.c | 468 ++ contrib/bind-9.2.4rc7/lib/bind/dst/md5.h | 101 + contrib/bind-9.2.4rc7/lib/bind/dst/md5_dgst.c | 370 + contrib/bind-9.2.4rc7/lib/bind/dst/md5_locl.h | 190 + contrib/bind-9.2.4rc7/lib/bind/dst/support.c | 350 + .../lib/bind/include/arpa/inet.h | 124 + .../lib/bind/include/arpa/nameser.h | 576 ++ .../lib/bind/include/arpa/nameser_compat.h | 232 + .../lib/bind/include/fd_setsize.h | 9 + .../bind-9.2.4rc7/lib/bind/include/hesiod.h | 38 + contrib/bind-9.2.4rc7/lib/bind/include/irp.h | 103 + contrib/bind-9.2.4rc7/lib/bind/include/irs.h | 345 + .../lib/bind/include/isc/assertions.h | 122 + .../bind-9.2.4rc7/lib/bind/include/isc/ctl.h | 109 + .../bind-9.2.4rc7/lib/bind/include/isc/dst.h | 180 + .../lib/bind/include/isc/eventlib.h | 200 + .../bind-9.2.4rc7/lib/bind/include/isc/heap.h | 47 + .../lib/bind/include/isc/irpmarshall.h | 115 + .../bind-9.2.4rc7/lib/bind/include/isc/list.h | 112 + .../lib/bind/include/isc/logging.h | 112 + .../lib/bind/include/isc/memcluster.h | 49 + .../bind-9.2.4rc7/lib/bind/include/isc/misc.h | 39 + .../bind-9.2.4rc7/lib/bind/include/isc/tree.h | 58 + .../bind-9.2.4rc7/lib/bind/include/netdb.h | 549 ++ .../bind-9.2.4rc7/lib/bind/include/netgroup.h | 24 + .../lib/bind/include/res_update.h | 65 + .../bind-9.2.4rc7/lib/bind/include/resolv.h | 501 ++ .../bind-9.2.4rc7/lib/bind/inet/inet_addr.c | 206 + .../lib/bind/inet/inet_cidr_ntop.c | 259 + .../lib/bind/inet/inet_cidr_pton.c | 275 + .../bind-9.2.4rc7/lib/bind/inet/inet_data.c | 44 + .../bind-9.2.4rc7/lib/bind/inet/inet_lnaof.c | 63 + .../lib/bind/inet/inet_makeaddr.c | 66 + .../lib/bind/inet/inet_net_ntop.c | 277 + .../lib/bind/inet/inet_net_pton.c | 405 ++ .../bind-9.2.4rc7/lib/bind/inet/inet_neta.c | 87 + .../bind-9.2.4rc7/lib/bind/inet/inet_netof.c | 62 + .../lib/bind/inet/inet_network.c | 104 + .../bind-9.2.4rc7/lib/bind/inet/inet_ntoa.c | 62 + .../bind-9.2.4rc7/lib/bind/inet/inet_ntop.c | 203 + .../bind-9.2.4rc7/lib/bind/inet/inet_pton.c | 222 + .../bind-9.2.4rc7/lib/bind/inet/nsap_addr.c | 108 + contrib/bind-9.2.4rc7/lib/bind/irs/dns.c | 153 + contrib/bind-9.2.4rc7/lib/bind/irs/dns_gr.c | 293 + contrib/bind-9.2.4rc7/lib/bind/irs/dns_ho.c | 1150 +++ contrib/bind-9.2.4rc7/lib/bind/irs/dns_nw.c | 589 ++ contrib/bind-9.2.4rc7/lib/bind/irs/dns_p.h | 50 + contrib/bind-9.2.4rc7/lib/bind/irs/dns_pr.c | 266 + contrib/bind-9.2.4rc7/lib/bind/irs/dns_pw.c | 231 + contrib/bind-9.2.4rc7/lib/bind/irs/dns_sv.c | 298 + .../bind-9.2.4rc7/lib/bind/irs/gai_strerror.c | 86 + contrib/bind-9.2.4rc7/lib/bind/irs/gen.c | 430 ++ contrib/bind-9.2.4rc7/lib/bind/irs/gen_gr.c | 492 ++ contrib/bind-9.2.4rc7/lib/bind/irs/gen_ho.c | 391 ++ contrib/bind-9.2.4rc7/lib/bind/irs/gen_ng.c | 172 + contrib/bind-9.2.4rc7/lib/bind/irs/gen_nw.c | 262 + contrib/bind-9.2.4rc7/lib/bind/irs/gen_p.h | 113 + contrib/bind-9.2.4rc7/lib/bind/irs/gen_pr.c | 226 + contrib/bind-9.2.4rc7/lib/bind/irs/gen_pw.c | 233 + contrib/bind-9.2.4rc7/lib/bind/irs/gen_sv.c | 227 + .../bind-9.2.4rc7/lib/bind/irs/getaddrinfo.c | 1226 ++++ contrib/bind-9.2.4rc7/lib/bind/irs/getgrent.c | 223 + .../bind-9.2.4rc7/lib/bind/irs/getgrent_r.c | 229 + .../bind-9.2.4rc7/lib/bind/irs/gethostent.c | 1069 +++ .../bind-9.2.4rc7/lib/bind/irs/gethostent_r.c | 262 + .../bind-9.2.4rc7/lib/bind/irs/getnameinfo.c | 322 + .../bind-9.2.4rc7/lib/bind/irs/getnetent.c | 343 + .../bind-9.2.4rc7/lib/bind/irs/getnetent_r.c | 227 + .../bind-9.2.4rc7/lib/bind/irs/getnetgrent.c | 156 + .../lib/bind/irs/getnetgrent_r.c | 167 + .../bind-9.2.4rc7/lib/bind/irs/getprotoent.c | 174 + .../lib/bind/irs/getprotoent_r.c | 216 + contrib/bind-9.2.4rc7/lib/bind/irs/getpwent.c | 200 + .../bind-9.2.4rc7/lib/bind/irs/getpwent_r.c | 275 + .../bind-9.2.4rc7/lib/bind/irs/getservent.c | 177 + .../bind-9.2.4rc7/lib/bind/irs/getservent_r.c | 237 + contrib/bind-9.2.4rc7/lib/bind/irs/hesiod.c | 507 ++ contrib/bind-9.2.4rc7/lib/bind/irs/hesiod_p.h | 48 + contrib/bind-9.2.4rc7/lib/bind/irs/irp.c | 592 ++ contrib/bind-9.2.4rc7/lib/bind/irs/irp_gr.c | 408 ++ contrib/bind-9.2.4rc7/lib/bind/irs/irp_ho.c | 429 ++ contrib/bind-9.2.4rc7/lib/bind/irs/irp_ng.c | 272 + contrib/bind-9.2.4rc7/lib/bind/irs/irp_nw.c | 375 + contrib/bind-9.2.4rc7/lib/bind/irs/irp_p.h | 59 + contrib/bind-9.2.4rc7/lib/bind/irs/irp_pr.c | 353 + contrib/bind-9.2.4rc7/lib/bind/irs/irp_pw.c | 358 + contrib/bind-9.2.4rc7/lib/bind/irs/irp_sv.c | 369 + .../bind-9.2.4rc7/lib/bind/irs/irpmarshall.c | 2344 +++++++ contrib/bind-9.2.4rc7/lib/bind/irs/irs_data.c | 230 + contrib/bind-9.2.4rc7/lib/bind/irs/irs_data.h | 62 + contrib/bind-9.2.4rc7/lib/bind/irs/irs_p.h | 49 + contrib/bind-9.2.4rc7/lib/bind/irs/lcl.c | 140 + contrib/bind-9.2.4rc7/lib/bind/irs/lcl_gr.c | 354 + contrib/bind-9.2.4rc7/lib/bind/irs/lcl_ho.c | 576 ++ contrib/bind-9.2.4rc7/lib/bind/irs/lcl_ng.c | 444 ++ contrib/bind-9.2.4rc7/lib/bind/irs/lcl_nw.c | 371 + contrib/bind-9.2.4rc7/lib/bind/irs/lcl_p.h | 50 + contrib/bind-9.2.4rc7/lib/bind/irs/lcl_pr.c | 284 + contrib/bind-9.2.4rc7/lib/bind/irs/lcl_pw.c | 308 + contrib/bind-9.2.4rc7/lib/bind/irs/lcl_sv.c | 431 ++ contrib/bind-9.2.4rc7/lib/bind/irs/nis.c | 154 + contrib/bind-9.2.4rc7/lib/bind/irs/nis_gr.c | 353 + contrib/bind-9.2.4rc7/lib/bind/irs/nis_ho.c | 533 ++ contrib/bind-9.2.4rc7/lib/bind/irs/nis_ng.c | 302 + contrib/bind-9.2.4rc7/lib/bind/irs/nis_nw.c | 383 + contrib/bind-9.2.4rc7/lib/bind/irs/nis_p.h | 46 + contrib/bind-9.2.4rc7/lib/bind/irs/nis_pr.c | 300 + contrib/bind-9.2.4rc7/lib/bind/irs/nis_pw.c | 287 + contrib/bind-9.2.4rc7/lib/bind/irs/nis_sv.c | 308 + contrib/bind-9.2.4rc7/lib/bind/irs/nul_ng.c | 126 + .../bind-9.2.4rc7/lib/bind/irs/pathnames.h | 50 + contrib/bind-9.2.4rc7/lib/bind/irs/util.c | 107 + .../bind-9.2.4rc7/lib/bind/isc/assertions.c | 91 + .../lib/bind/isc/assertions.mdoc | 138 + contrib/bind-9.2.4rc7/lib/bind/isc/base64.c | 320 + contrib/bind-9.2.4rc7/lib/bind/isc/bitncmp.c | 66 + .../bind-9.2.4rc7/lib/bind/isc/bitncmp.mdoc | 82 + contrib/bind-9.2.4rc7/lib/bind/isc/ctl_clnt.c | 602 ++ contrib/bind-9.2.4rc7/lib/bind/isc/ctl_p.c | 186 + contrib/bind-9.2.4rc7/lib/bind/isc/ctl_p.h | 26 + contrib/bind-9.2.4rc7/lib/bind/isc/ctl_srvr.c | 780 +++ .../bind-9.2.4rc7/lib/bind/isc/ev_connects.c | 367 + contrib/bind-9.2.4rc7/lib/bind/isc/ev_files.c | 283 + .../bind-9.2.4rc7/lib/bind/isc/ev_streams.c | 306 + .../bind-9.2.4rc7/lib/bind/isc/ev_timers.c | 497 ++ contrib/bind-9.2.4rc7/lib/bind/isc/ev_waits.c | 245 + contrib/bind-9.2.4rc7/lib/bind/isc/eventlib.c | 728 ++ .../bind-9.2.4rc7/lib/bind/isc/eventlib.mdoc | 918 +++ .../bind-9.2.4rc7/lib/bind/isc/eventlib_p.h | 219 + contrib/bind-9.2.4rc7/lib/bind/isc/heap.c | 230 + contrib/bind-9.2.4rc7/lib/bind/isc/heap.mdoc | 378 + contrib/bind-9.2.4rc7/lib/bind/isc/hex.c | 116 + contrib/bind-9.2.4rc7/lib/bind/isc/logging.c | 720 ++ .../bind-9.2.4rc7/lib/bind/isc/logging.mdoc | 1056 +++ .../bind-9.2.4rc7/lib/bind/isc/logging_p.h | 60 + .../bind-9.2.4rc7/lib/bind/isc/memcluster.c | 545 ++ .../lib/bind/isc/memcluster.mdoc | 376 + contrib/bind-9.2.4rc7/lib/bind/isc/movefile.c | 35 + contrib/bind-9.2.4rc7/lib/bind/isc/tree.c | 532 ++ contrib/bind-9.2.4rc7/lib/bind/isc/tree.mdoc | 154 + contrib/bind-9.2.4rc7/lib/bind/ltmain.sh | 4950 +++++++++++++ .../bind-9.2.4rc7/lib/bind/make/includes.in | 44 + contrib/bind-9.2.4rc7/lib/bind/make/mkdep.in | 147 + contrib/bind-9.2.4rc7/lib/bind/make/rules.in | 177 + contrib/bind-9.2.4rc7/lib/bind/mkinstalldirs | 40 + .../bind-9.2.4rc7/lib/bind/nameser/ns_date.c | 128 + .../bind-9.2.4rc7/lib/bind/nameser/ns_name.c | 963 +++ .../lib/bind/nameser/ns_netint.c | 56 + .../bind-9.2.4rc7/lib/bind/nameser/ns_parse.c | 203 + .../bind-9.2.4rc7/lib/bind/nameser/ns_print.c | 898 +++ .../lib/bind/nameser/ns_samedomain.c | 206 + .../bind-9.2.4rc7/lib/bind/nameser/ns_sign.c | 380 + .../bind-9.2.4rc7/lib/bind/nameser/ns_ttl.c | 159 + .../lib/bind/nameser/ns_verify.c | 480 ++ .../bind/port/freebsd/include/sys/bitypes.h | 37 + .../bind-9.2.4rc7/lib/bind/port_after.h.in | 395 ++ .../bind-9.2.4rc7/lib/bind/port_before.h.in | 138 + .../bind-9.2.4rc7/lib/bind/resolv/herror.c | 127 + .../bind-9.2.4rc7/lib/bind/resolv/res_comp.c | 251 + .../bind-9.2.4rc7/lib/bind/resolv/res_data.c | 291 + .../bind-9.2.4rc7/lib/bind/resolv/res_debug.c | 1163 ++++ .../bind-9.2.4rc7/lib/bind/resolv/res_debug.h | 34 + .../lib/bind/resolv/res_findzonecut.c | 722 ++ .../bind-9.2.4rc7/lib/bind/resolv/res_init.c | 740 ++ .../lib/bind/resolv/res_mkquery.c | 256 + .../lib/bind/resolv/res_mkupdate.c | 1159 ++++ .../lib/bind/resolv/res_mkupdate.h | 24 + .../lib/bind/resolv/res_private.h | 20 + .../bind-9.2.4rc7/lib/bind/resolv/res_query.c | 432 ++ .../bind-9.2.4rc7/lib/bind/resolv/res_send.c | 1052 +++ .../lib/bind/resolv/res_sendsigned.c | 159 + .../lib/bind/resolv/res_update.c | 212 + contrib/bind-9.2.4rc7/lib/dns/a6.c | 237 + contrib/bind-9.2.4rc7/lib/dns/acl.c | 422 ++ contrib/bind-9.2.4rc7/lib/dns/adb.c | 4124 +++++++++++ contrib/bind-9.2.4rc7/lib/dns/api | 3 + contrib/bind-9.2.4rc7/lib/dns/byaddr.c | 325 + contrib/bind-9.2.4rc7/lib/dns/cache.c | 963 +++ contrib/bind-9.2.4rc7/lib/dns/callbacks.c | 111 + contrib/bind-9.2.4rc7/lib/dns/compress.c | 316 + contrib/bind-9.2.4rc7/lib/dns/db.c | 793 +++ contrib/bind-9.2.4rc7/lib/dns/dbiterator.c | 141 + contrib/bind-9.2.4rc7/lib/dns/dbtable.c | 291 + contrib/bind-9.2.4rc7/lib/dns/diff.c | 528 ++ contrib/bind-9.2.4rc7/lib/dns/dispatch.c | 2105 ++++++ contrib/bind-9.2.4rc7/lib/dns/dnssec.c | 817 +++ contrib/bind-9.2.4rc7/lib/dns/forward.c | 195 + contrib/bind-9.2.4rc7/lib/dns/gen-unix.h | 92 + contrib/bind-9.2.4rc7/lib/dns/gen-win32.h | 290 + contrib/bind-9.2.4rc7/lib/dns/gen.c | 864 +++ .../bind-9.2.4rc7/lib/dns/include/dns/a6.h | 82 + .../bind-9.2.4rc7/lib/dns/include/dns/acl.h | 204 + .../bind-9.2.4rc7/lib/dns/include/dns/adb.h | 574 ++ .../bind-9.2.4rc7/lib/dns/include/dns/bit.h | 37 + .../lib/dns/include/dns/byaddr.h | 165 + .../bind-9.2.4rc7/lib/dns/include/dns/cache.h | 240 + .../lib/dns/include/dns/callbacks.h | 83 + .../bind-9.2.4rc7/lib/dns/include/dns/cert.h | 67 + .../lib/dns/include/dns/compress.h | 248 + .../bind-9.2.4rc7/lib/dns/include/dns/db.h | 1244 ++++ .../lib/dns/include/dns/dbiterator.h | 298 + .../lib/dns/include/dns/dbtable.h | 164 + .../bind-9.2.4rc7/lib/dns/include/dns/diff.h | 274 + .../lib/dns/include/dns/dispatch.h | 420 ++ .../lib/dns/include/dns/dnssec.h | 164 + .../lib/dns/include/dns/events.h | 69 + .../lib/dns/include/dns/fixedname.h | 83 + .../lib/dns/include/dns/forward.h | 98 + .../lib/dns/include/dns/journal.h | 263 + .../lib/dns/include/dns/keyflags.h | 52 + .../lib/dns/include/dns/keytable.h | 255 + .../lib/dns/include/dns/keyvalues.h | 92 + .../bind-9.2.4rc7/lib/dns/include/dns/lib.h | 39 + .../bind-9.2.4rc7/lib/dns/include/dns/log.h | 103 + .../lib/dns/include/dns/lookup.h | 138 + .../lib/dns/include/dns/master.h | 186 + .../lib/dns/include/dns/masterdump.h | 181 + .../lib/dns/include/dns/message.h | 1263 ++++ .../bind-9.2.4rc7/lib/dns/include/dns/name.h | 1361 ++++ .../lib/dns/include/dns/ncache.h | 122 + .../bind-9.2.4rc7/lib/dns/include/dns/nxt.h | 68 + .../bind-9.2.4rc7/lib/dns/include/dns/peer.h | 170 + .../bind-9.2.4rc7/lib/dns/include/dns/rbt.h | 823 +++ .../bind-9.2.4rc7/lib/dns/include/dns/rcode.h | 96 + .../bind-9.2.4rc7/lib/dns/include/dns/rdata.h | 652 ++ .../lib/dns/include/dns/rdataclass.h | 79 + .../lib/dns/include/dns/rdatalist.h | 104 + .../lib/dns/include/dns/rdataset.h | 418 ++ .../lib/dns/include/dns/rdatasetiter.h | 171 + .../lib/dns/include/dns/rdataslab.h | 151 + .../lib/dns/include/dns/rdatatype.h | 81 + .../lib/dns/include/dns/request.h | 336 + .../lib/dns/include/dns/resolver.h | 354 + .../lib/dns/include/dns/result.h | 171 + .../lib/dns/include/dns/rootns.h | 35 + .../bind-9.2.4rc7/lib/dns/include/dns/sdb.h | 192 + .../lib/dns/include/dns/secalg.h | 69 + .../lib/dns/include/dns/secproto.h | 69 + .../bind-9.2.4rc7/lib/dns/include/dns/soa.h | 80 + .../bind-9.2.4rc7/lib/dns/include/dns/ssu.h | 157 + .../bind-9.2.4rc7/lib/dns/include/dns/stats.h | 57 + .../lib/dns/include/dns/tcpmsg.h | 145 + .../bind-9.2.4rc7/lib/dns/include/dns/time.h | 70 + .../bind-9.2.4rc7/lib/dns/include/dns/timer.h | 50 + .../bind-9.2.4rc7/lib/dns/include/dns/tkey.h | 196 + .../bind-9.2.4rc7/lib/dns/include/dns/tsig.h | 242 + .../bind-9.2.4rc7/lib/dns/include/dns/ttl.h | 76 + .../bind-9.2.4rc7/lib/dns/include/dns/types.h | 304 + .../lib/dns/include/dns/validator.h | 186 + .../bind-9.2.4rc7/lib/dns/include/dns/view.h | 769 ++ .../bind-9.2.4rc7/lib/dns/include/dns/xfrin.h | 99 + .../bind-9.2.4rc7/lib/dns/include/dns/zone.h | 1327 ++++ .../lib/dns/include/dns/zonekey.h | 40 + .../bind-9.2.4rc7/lib/dns/include/dns/zt.h | 167 + contrib/bind-9.2.4rc7/lib/dns/journal.c | 1908 +++++ contrib/bind-9.2.4rc7/lib/dns/keytable.c | 396 ++ contrib/bind-9.2.4rc7/lib/dns/lib.c | 62 + contrib/bind-9.2.4rc7/lib/dns/log.c | 93 + contrib/bind-9.2.4rc7/lib/dns/lookup.c | 492 ++ contrib/bind-9.2.4rc7/lib/dns/master.c | 2105 ++++++ contrib/bind-9.2.4rc7/lib/dns/masterdump.c | 1129 +++ contrib/bind-9.2.4rc7/lib/dns/message.c | 3093 +++++++++ contrib/bind-9.2.4rc7/lib/dns/name.c | 3342 +++++++++ contrib/bind-9.2.4rc7/lib/dns/ncache.c | 379 + contrib/bind-9.2.4rc7/lib/dns/nxt.c | 186 + contrib/bind-9.2.4rc7/lib/dns/peer.c | 502 ++ contrib/bind-9.2.4rc7/lib/dns/rbt.c | 2682 +++++++ contrib/bind-9.2.4rc7/lib/dns/rbtdb.c | 5385 ++++++++++++++ contrib/bind-9.2.4rc7/lib/dns/rbtdb.h | 43 + contrib/bind-9.2.4rc7/lib/dns/rbtdb64.c | 21 + contrib/bind-9.2.4rc7/lib/dns/rbtdb64.h | 44 + contrib/bind-9.2.4rc7/lib/dns/rdata.c | 2087 ++++++ .../lib/dns/rdata/any_255/tsig_250.c | 566 ++ .../lib/dns/rdata/any_255/tsig_250.h | 39 + .../lib/dns/rdata/generic/afsdb_18.c | 267 + .../lib/dns/rdata/generic/afsdb_18.h | 33 + .../lib/dns/rdata/generic/cert_37.c | 254 + .../lib/dns/rdata/generic/cert_37.h | 34 + .../lib/dns/rdata/generic/cname_5.c | 207 + .../lib/dns/rdata/generic/cname_5.h | 29 + .../lib/dns/rdata/generic/dname_39.c | 208 + .../lib/dns/rdata/generic/dname_39.h | 31 + .../lib/dns/rdata/generic/gpos_27.c | 227 + .../lib/dns/rdata/generic/gpos_27.h | 36 + .../lib/dns/rdata/generic/hinfo_13.c | 199 + .../lib/dns/rdata/generic/hinfo_13.h | 32 + .../lib/dns/rdata/generic/isdn_20.c | 209 + .../lib/dns/rdata/generic/isdn_20.h | 34 + .../lib/dns/rdata/generic/key_25.c | 287 + .../lib/dns/rdata/generic/key_25.h | 36 + .../lib/dns/rdata/generic/loc_29.c | 740 ++ .../lib/dns/rdata/generic/loc_29.h | 42 + .../lib/dns/rdata/generic/mb_7.c | 210 + .../lib/dns/rdata/generic/mb_7.h | 29 + .../lib/dns/rdata/generic/md_3.c | 211 + .../lib/dns/rdata/generic/md_3.h | 30 + .../lib/dns/rdata/generic/mf_4.c | 210 + .../lib/dns/rdata/generic/mf_4.h | 29 + .../lib/dns/rdata/generic/mg_8.c | 206 + .../lib/dns/rdata/generic/mg_8.h | 29 + .../lib/dns/rdata/generic/minfo_14.c | 276 + .../lib/dns/rdata/generic/minfo_14.h | 30 + .../lib/dns/rdata/generic/mr_9.c | 206 + .../lib/dns/rdata/generic/mr_9.h | 29 + .../lib/dns/rdata/generic/mx_15.c | 248 + .../lib/dns/rdata/generic/mx_15.h | 30 + .../lib/dns/rdata/generic/ns_2.c | 210 + .../lib/dns/rdata/generic/ns_2.h | 30 + .../lib/dns/rdata/generic/null_10.c | 167 + .../lib/dns/rdata/generic/null_10.h | 31 + .../lib/dns/rdata/generic/nxt_30.c | 304 + .../lib/dns/rdata/generic/nxt_30.h | 33 + .../lib/dns/rdata/generic/opt_41.c | 256 + .../lib/dns/rdata/generic/opt_41.h | 54 + .../lib/dns/rdata/generic/proforma.c | 146 + .../lib/dns/rdata/generic/proforma.h | 29 + .../lib/dns/rdata/generic/ptr_12.c | 207 + .../lib/dns/rdata/generic/ptr_12.h | 29 + .../lib/dns/rdata/generic/rp_17.c | 273 + .../lib/dns/rdata/generic/rp_17.h | 33 + .../lib/dns/rdata/generic/rt_21.c | 269 + .../lib/dns/rdata/generic/rt_21.h | 32 + .../lib/dns/rdata/generic/sig_24.c | 553 ++ .../lib/dns/rdata/generic/sig_24.h | 41 + .../lib/dns/rdata/generic/soa_6.c | 387 ++ .../lib/dns/rdata/generic/soa_6.h | 36 + .../lib/dns/rdata/generic/tkey_249.c | 530 ++ .../lib/dns/rdata/generic/tkey_249.h | 40 + .../lib/dns/rdata/generic/txt_16.c | 213 + .../lib/dns/rdata/generic/txt_16.h | 51 + .../lib/dns/rdata/generic/unspec_103.c | 164 + .../lib/dns/rdata/generic/unspec_103.h | 30 + .../lib/dns/rdata/generic/x25_19.c | 194 + .../lib/dns/rdata/generic/x25_19.h | 32 + .../bind-9.2.4rc7/lib/dns/rdata/hs_4/a_1.c | 205 + .../bind-9.2.4rc7/lib/dns/rdata/hs_4/a_1.h | 28 + .../bind-9.2.4rc7/lib/dns/rdata/in_1/a6_38.c | 415 ++ .../bind-9.2.4rc7/lib/dns/rdata/in_1/a6_38.h | 33 + .../bind-9.2.4rc7/lib/dns/rdata/in_1/a_1.c | 211 + .../bind-9.2.4rc7/lib/dns/rdata/in_1/a_1.h | 28 + .../lib/dns/rdata/in_1/aaaa_28.c | 208 + .../lib/dns/rdata/in_1/aaaa_28.h | 30 + .../bind-9.2.4rc7/lib/dns/rdata/in_1/kx_36.c | 261 + .../bind-9.2.4rc7/lib/dns/rdata/in_1/kx_36.h | 32 + .../lib/dns/rdata/in_1/naptr_35.c | 551 ++ .../lib/dns/rdata/in_1/naptr_35.h | 39 + .../lib/dns/rdata/in_1/nsap-ptr_23.c | 218 + .../lib/dns/rdata/in_1/nsap-ptr_23.h | 31 + .../lib/dns/rdata/in_1/nsap_22.c | 228 + .../lib/dns/rdata/in_1/nsap_22.h | 32 + .../bind-9.2.4rc7/lib/dns/rdata/in_1/px_26.c | 347 + .../bind-9.2.4rc7/lib/dns/rdata/in_1/px_26.h | 33 + .../bind-9.2.4rc7/lib/dns/rdata/in_1/srv_33.c | 329 + .../bind-9.2.4rc7/lib/dns/rdata/in_1/srv_33.h | 36 + .../bind-9.2.4rc7/lib/dns/rdata/in_1/wks_11.c | 324 + .../bind-9.2.4rc7/lib/dns/rdata/in_1/wks_11.h | 32 + .../lib/dns/rdata/rdatastructpre.h | 42 + .../lib/dns/rdata/rdatastructsuf.h | 22 + contrib/bind-9.2.4rc7/lib/dns/rdatalist.c | 152 + contrib/bind-9.2.4rc7/lib/dns/rdatalist_p.h | 48 + contrib/bind-9.2.4rc7/lib/dns/rdataset.c | 555 ++ contrib/bind-9.2.4rc7/lib/dns/rdatasetiter.c | 78 + contrib/bind-9.2.4rc7/lib/dns/rdataslab.c | 597 ++ contrib/bind-9.2.4rc7/lib/dns/request.c | 1353 ++++ contrib/bind-9.2.4rc7/lib/dns/resolver.c | 5384 ++++++++++++++ contrib/bind-9.2.4rc7/lib/dns/result.c | 265 + contrib/bind-9.2.4rc7/lib/dns/rootns.c | 246 + contrib/bind-9.2.4rc7/lib/dns/sdb.c | 1471 ++++ .../bind-9.2.4rc7/lib/dns/sec/dst/dst_api.c | 1119 +++ .../lib/dns/sec/dst/dst_internal.h | 142 + .../bind-9.2.4rc7/lib/dns/sec/dst/dst_lib.c | 65 + .../bind-9.2.4rc7/lib/dns/sec/dst/dst_parse.c | 432 ++ .../bind-9.2.4rc7/lib/dns/sec/dst/dst_parse.h | 95 + .../lib/dns/sec/dst/dst_result.c | 85 + .../lib/dns/sec/dst/gssapi_link.c | 229 + .../bind-9.2.4rc7/lib/dns/sec/dst/gssapictx.c | 262 + .../bind-9.2.4rc7/lib/dns/sec/dst/hmac_link.c | 290 + .../lib/dns/sec/dst/include/dst/dst.h | 545 ++ .../lib/dns/sec/dst/include/dst/gssapi.h | 56 + .../lib/dns/sec/dst/include/dst/lib.h | 39 + .../lib/dns/sec/dst/include/dst/result.h | 67 + contrib/bind-9.2.4rc7/lib/dns/sec/dst/key.c | 126 + .../lib/dns/sec/dst/openssl_link.c | 167 + .../lib/dns/sec/dst/openssldh_link.c | 572 ++ .../lib/dns/sec/dst/openssldsa_link.c | 444 ++ .../lib/dns/sec/dst/opensslrsa_link.c | 519 ++ contrib/bind-9.2.4rc7/lib/dns/soa.c | 109 + contrib/bind-9.2.4rc7/lib/dns/ssu.c | 357 + contrib/bind-9.2.4rc7/lib/dns/stats.c | 53 + contrib/bind-9.2.4rc7/lib/dns/tcpmsg.c | 240 + contrib/bind-9.2.4rc7/lib/dns/time.c | 171 + contrib/bind-9.2.4rc7/lib/dns/timer.c | 58 + contrib/bind-9.2.4rc7/lib/dns/tkey.c | 1244 ++++ contrib/bind-9.2.4rc7/lib/dns/tsig.c | 1216 ++++ contrib/bind-9.2.4rc7/lib/dns/ttl.c | 205 + contrib/bind-9.2.4rc7/lib/dns/validator.c | 1695 +++++ contrib/bind-9.2.4rc7/lib/dns/version.c | 24 + contrib/bind-9.2.4rc7/lib/dns/view.c | 1303 ++++ contrib/bind-9.2.4rc7/lib/dns/xfrin.c | 1385 ++++ contrib/bind-9.2.4rc7/lib/dns/zone.c | 6159 +++++++++++++++++ contrib/bind-9.2.4rc7/lib/dns/zonekey.c | 53 + contrib/bind-9.2.4rc7/lib/dns/zt.c | 316 + contrib/bind-9.2.4rc7/lib/isc/api | 3 + contrib/bind-9.2.4rc7/lib/isc/assertions.c | 93 + contrib/bind-9.2.4rc7/lib/isc/base64.c | 246 + contrib/bind-9.2.4rc7/lib/isc/bitstring.c | 125 + contrib/bind-9.2.4rc7/lib/isc/buffer.c | 411 ++ contrib/bind-9.2.4rc7/lib/isc/bufferlist.c | 62 + contrib/bind-9.2.4rc7/lib/isc/commandline.c | 222 + contrib/bind-9.2.4rc7/lib/isc/entropy.c | 1250 ++++ contrib/bind-9.2.4rc7/lib/isc/error.c | 101 + contrib/bind-9.2.4rc7/lib/isc/event.c | 87 + contrib/bind-9.2.4rc7/lib/isc/fsaccess.c | 101 + contrib/bind-9.2.4rc7/lib/isc/hash.c | 387 ++ contrib/bind-9.2.4rc7/lib/isc/heap.c | 252 + contrib/bind-9.2.4rc7/lib/isc/hex.c | 199 + contrib/bind-9.2.4rc7/lib/isc/hmacmd5.c | 113 + .../bind-9.2.4rc7/lib/isc/include/isc/app.h | 212 + .../lib/isc/include/isc/assertions.h | 120 + .../lib/isc/include/isc/base64.h | 97 + .../lib/isc/include/isc/bitstring.h | 152 + .../lib/isc/include/isc/boolean.h | 29 + .../lib/isc/include/isc/buffer.h | 800 +++ .../lib/isc/include/isc/bufferlist.h | 86 + .../lib/isc/include/isc/commandline.h | 47 + .../lib/isc/include/isc/entropy.h | 288 + .../bind-9.2.4rc7/lib/isc/include/isc/error.h | 55 + .../bind-9.2.4rc7/lib/isc/include/isc/event.h | 115 + .../lib/isc/include/isc/eventclass.h | 53 + .../bind-9.2.4rc7/lib/isc/include/isc/file.h | 246 + .../lib/isc/include/isc/formatcheck.h | 34 + .../lib/isc/include/isc/fsaccess.h | 177 + .../bind-9.2.4rc7/lib/isc/include/isc/hash.h | 175 + .../bind-9.2.4rc7/lib/isc/include/isc/heap.h | 51 + .../bind-9.2.4rc7/lib/isc/include/isc/hex.h | 96 + .../lib/isc/include/isc/hmacmd5.h | 60 + .../lib/isc/include/isc/interfaceiter.h | 134 + .../bind-9.2.4rc7/lib/isc/include/isc/ipv6.h | 140 + .../bind-9.2.4rc7/lib/isc/include/isc/lang.h | 31 + .../bind-9.2.4rc7/lib/isc/include/isc/lex.h | 395 ++ .../bind-9.2.4rc7/lib/isc/include/isc/lfsr.h | 133 + .../bind-9.2.4rc7/lib/isc/include/isc/lib.h | 39 + .../bind-9.2.4rc7/lib/isc/include/isc/list.h | 180 + .../bind-9.2.4rc7/lib/isc/include/isc/log.h | 880 +++ .../bind-9.2.4rc7/lib/isc/include/isc/magic.h | 40 + .../bind-9.2.4rc7/lib/isc/include/isc/md5.h | 72 + .../bind-9.2.4rc7/lib/isc/include/isc/mem.h | 437 ++ .../lib/isc/include/isc/msgcat.h | 132 + .../bind-9.2.4rc7/lib/isc/include/isc/msgs.h | 180 + .../lib/isc/include/isc/mutexblock.h | 69 + .../lib/isc/include/isc/netaddr.h | 130 + .../lib/isc/include/isc/ondestroy.h | 108 + .../bind-9.2.4rc7/lib/isc/include/isc/os.h | 36 + .../lib/isc/include/isc/platform.h.in | 197 + .../bind-9.2.4rc7/lib/isc/include/isc/print.h | 69 + .../bind-9.2.4rc7/lib/isc/include/isc/quota.h | 106 + .../lib/isc/include/isc/random.h | 60 + .../lib/isc/include/isc/ratelimiter.h | 120 + .../lib/isc/include/isc/refcount.h | 164 + .../lib/isc/include/isc/region.h | 80 + .../lib/isc/include/isc/resource.h | 85 + .../lib/isc/include/isc/result.h | 105 + .../lib/isc/include/isc/resultclass.h | 54 + .../lib/isc/include/isc/rwlock.h | 95 + .../lib/isc/include/isc/serial.h | 76 + .../bind-9.2.4rc7/lib/isc/include/isc/sha1.h | 58 + .../lib/isc/include/isc/sockaddr.h | 187 + .../lib/isc/include/isc/socket.h | 687 ++ .../bind-9.2.4rc7/lib/isc/include/isc/stdio.h | 67 + .../lib/isc/include/isc/string.h | 56 + .../lib/isc/include/isc/symtab.h | 127 + .../bind-9.2.4rc7/lib/isc/include/isc/task.h | 601 ++ .../lib/isc/include/isc/taskpool.h | 107 + .../bind-9.2.4rc7/lib/isc/include/isc/timer.h | 327 + .../bind-9.2.4rc7/lib/isc/include/isc/types.h | 103 + .../bind-9.2.4rc7/lib/isc/include/isc/util.h | 211 + contrib/bind-9.2.4rc7/lib/isc/inet_aton.c | 195 + contrib/bind-9.2.4rc7/lib/isc/inet_ntop.c | 194 + contrib/bind-9.2.4rc7/lib/isc/inet_pton.c | 211 + contrib/bind-9.2.4rc7/lib/isc/lex.c | 904 +++ contrib/bind-9.2.4rc7/lib/isc/lfsr.c | 161 + contrib/bind-9.2.4rc7/lib/isc/lib.c | 77 + contrib/bind-9.2.4rc7/lib/isc/log.c | 1773 +++++ contrib/bind-9.2.4rc7/lib/isc/md5.c | 249 + contrib/bind-9.2.4rc7/lib/isc/mem.c | 1726 +++++ contrib/bind-9.2.4rc7/lib/isc/mutexblock.c | 57 + contrib/bind-9.2.4rc7/lib/isc/netaddr.c | 285 + contrib/bind-9.2.4rc7/lib/isc/nls/msgcat.c | 129 + .../lib/isc/nothreads/condition.c | 32 + .../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 + .../bind-9.2.4rc7/lib/isc/nothreads/mutex.c | 28 + .../bind-9.2.4rc7/lib/isc/nothreads/thread.c | 28 + contrib/bind-9.2.4rc7/lib/isc/ondestroy.c | 83 + contrib/bind-9.2.4rc7/lib/isc/print.c | 546 ++ .../lib/isc/pthreads/condition.c | 72 + .../lib/isc/pthreads/include/isc/condition.h | 63 + .../lib/isc/pthreads/include/isc/mutex.h | 131 + .../lib/isc/pthreads/include/isc/once.h | 48 + .../lib/isc/pthreads/include/isc/thread.h | 52 + .../bind-9.2.4rc7/lib/isc/pthreads/mutex.c | 222 + .../bind-9.2.4rc7/lib/isc/pthreads/thread.c | 68 + contrib/bind-9.2.4rc7/lib/isc/quota.c | 82 + contrib/bind-9.2.4rc7/lib/isc/random.c | 102 + contrib/bind-9.2.4rc7/lib/isc/ratelimiter.c | 276 + contrib/bind-9.2.4rc7/lib/isc/result.c | 208 + contrib/bind-9.2.4rc7/lib/isc/rwlock.c | 417 ++ contrib/bind-9.2.4rc7/lib/isc/serial.c | 56 + contrib/bind-9.2.4rc7/lib/isc/sha1.c | 309 + contrib/bind-9.2.4rc7/lib/isc/sockaddr.c | 429 ++ contrib/bind-9.2.4rc7/lib/isc/string.c | 111 + contrib/bind-9.2.4rc7/lib/isc/symtab.c | 250 + contrib/bind-9.2.4rc7/lib/isc/task.c | 1289 ++++ contrib/bind-9.2.4rc7/lib/isc/task_p.h | 29 + contrib/bind-9.2.4rc7/lib/isc/taskpool.c | 89 + contrib/bind-9.2.4rc7/lib/isc/timer.c | 864 +++ contrib/bind-9.2.4rc7/lib/isc/timer_p.h | 29 + contrib/bind-9.2.4rc7/lib/isc/unix/app.c | 664 ++ contrib/bind-9.2.4rc7/lib/isc/unix/dir.c | 253 + contrib/bind-9.2.4rc7/lib/isc/unix/entropy.c | 349 + .../bind-9.2.4rc7/lib/isc/unix/errno2result.c | 121 + .../bind-9.2.4rc7/lib/isc/unix/errno2result.h | 37 + contrib/bind-9.2.4rc7/lib/isc/unix/file.c | 315 + contrib/bind-9.2.4rc7/lib/isc/unix/fsaccess.c | 90 + .../bind-9.2.4rc7/lib/isc/unix/ifiter_ioctl.c | 404 ++ .../lib/isc/unix/ifiter_sysctl.c | 290 + .../lib/isc/unix/include/isc/dir.h | 100 + .../lib/isc/unix/include/isc/int.h | 53 + .../lib/isc/unix/include/isc/keyboard.h | 50 + .../lib/isc/unix/include/isc/net.h | 275 + .../lib/isc/unix/include/isc/netdb.h | 56 + .../lib/isc/unix/include/isc/offset.h | 44 + .../lib/isc/unix/include/isc/stat.h | 53 + .../lib/isc/unix/include/isc/stdtime.h | 47 + .../lib/isc/unix/include/isc/strerror.h | 43 + .../lib/isc/unix/include/isc/syslog.h | 45 + .../lib/isc/unix/include/isc/time.h | 298 + .../lib/isc/unix/interfaceiter.c | 152 + contrib/bind-9.2.4rc7/lib/isc/unix/ipv6.c | 23 + contrib/bind-9.2.4rc7/lib/isc/unix/keyboard.c | 126 + contrib/bind-9.2.4rc7/lib/isc/unix/net.c | 153 + contrib/bind-9.2.4rc7/lib/isc/unix/os.c | 92 + contrib/bind-9.2.4rc7/lib/isc/unix/resource.c | 204 + contrib/bind-9.2.4rc7/lib/isc/unix/socket.c | 3453 +++++++++ contrib/bind-9.2.4rc7/lib/isc/unix/socket_p.h | 33 + contrib/bind-9.2.4rc7/lib/isc/unix/stdio.c | 117 + contrib/bind-9.2.4rc7/lib/isc/unix/stdtime.c | 83 + contrib/bind-9.2.4rc7/lib/isc/unix/strerror.c | 74 + contrib/bind-9.2.4rc7/lib/isc/unix/syslog.c | 82 + contrib/bind-9.2.4rc7/lib/isc/unix/time.c | 409 ++ contrib/bind-9.2.4rc7/lib/isc/version.c | 24 + contrib/bind-9.2.4rc7/lib/isccc/alist.c | 297 + contrib/bind-9.2.4rc7/lib/isccc/api | 3 + contrib/bind-9.2.4rc7/lib/isccc/base64.c | 63 + contrib/bind-9.2.4rc7/lib/isccc/cc.c | 805 +++ contrib/bind-9.2.4rc7/lib/isccc/ccmsg.c | 220 + .../lib/isccc/include/isccc/alist.h | 72 + .../lib/isccc/include/isccc/base64.h | 70 + .../lib/isccc/include/isccc/cc.h | 88 + .../lib/isccc/include/isccc/ccmsg.h | 132 + .../lib/isccc/include/isccc/events.h | 35 + .../lib/isccc/include/isccc/lib.h | 40 + .../lib/isccc/include/isccc/result.h | 52 + .../lib/isccc/include/isccc/sexpr.h | 107 + .../lib/isccc/include/isccc/symtab.h | 123 + .../lib/isccc/include/isccc/symtype.h | 29 + .../lib/isccc/include/isccc/types.h | 38 + .../lib/isccc/include/isccc/util.h | 211 + contrib/bind-9.2.4rc7/lib/isccc/lib.c | 63 + contrib/bind-9.2.4rc7/lib/isccc/result.c | 70 + contrib/bind-9.2.4rc7/lib/isccc/sexpr.c | 310 + contrib/bind-9.2.4rc7/lib/isccc/symtab.c | 278 + contrib/bind-9.2.4rc7/lib/isccc/version.c | 24 + contrib/bind-9.2.4rc7/lib/isccfg/api | 3 + contrib/bind-9.2.4rc7/lib/isccfg/check.c | 737 ++ .../lib/isccfg/include/isccfg/cfg.h | 418 ++ .../lib/isccfg/include/isccfg/check.h | 54 + .../lib/isccfg/include/isccfg/log.h | 53 + contrib/bind-9.2.4rc7/lib/isccfg/log.c | 50 + contrib/bind-9.2.4rc7/lib/isccfg/parser.c | 3971 +++++++++++ contrib/bind-9.2.4rc7/lib/isccfg/version.c | 24 + contrib/bind-9.2.4rc7/lib/lwres/api | 3 + contrib/bind-9.2.4rc7/lib/lwres/assert_p.h | 33 + contrib/bind-9.2.4rc7/lib/lwres/context.c | 380 + contrib/bind-9.2.4rc7/lib/lwres/context_p.h | 59 + .../bind-9.2.4rc7/lib/lwres/gai_strerror.c | 52 + contrib/bind-9.2.4rc7/lib/lwres/getaddrinfo.c | 691 ++ contrib/bind-9.2.4rc7/lib/lwres/gethost.c | 219 + contrib/bind-9.2.4rc7/lib/lwres/getipnode.c | 848 +++ contrib/bind-9.2.4rc7/lib/lwres/getnameinfo.c | 285 + contrib/bind-9.2.4rc7/lib/lwres/getrrset.c | 211 + contrib/bind-9.2.4rc7/lib/lwres/herror.c | 101 + .../lib/lwres/include/lwres/context.h | 133 + .../lib/lwres/include/lwres/int.h | 32 + .../lib/lwres/include/lwres/ipv6.h | 118 + .../lib/lwres/include/lwres/lang.h | 31 + .../lib/lwres/include/lwres/list.h | 119 + .../lib/lwres/include/lwres/lwbuffer.h | 402 ++ .../lib/lwres/include/lwres/lwpacket.h | 124 + .../lib/lwres/include/lwres/lwres.h | 578 ++ .../lib/lwres/include/lwres/netdb.h.in | 518 ++ .../lib/lwres/include/lwres/platform.h.in | 91 + .../lib/lwres/include/lwres/result.h | 40 + contrib/bind-9.2.4rc7/lib/lwres/lwbuffer.c | 287 + contrib/bind-9.2.4rc7/lib/lwres/lwconfig.c | 703 ++ contrib/bind-9.2.4rc7/lib/lwres/lwinetaton.c | 203 + contrib/bind-9.2.4rc7/lib/lwres/lwinetntop.c | 191 + contrib/bind-9.2.4rc7/lib/lwres/lwinetpton.c | 206 + contrib/bind-9.2.4rc7/lib/lwres/lwpacket.c | 85 + contrib/bind-9.2.4rc7/lib/lwres/lwres_gabn.c | 415 ++ contrib/bind-9.2.4rc7/lib/lwres/lwres_gnba.c | 328 + contrib/bind-9.2.4rc7/lib/lwres/lwres_grbn.c | 416 ++ contrib/bind-9.2.4rc7/lib/lwres/lwres_noop.c | 255 + contrib/bind-9.2.4rc7/lib/lwres/lwresutil.c | 491 ++ contrib/bind-9.2.4rc7/lib/lwres/man/lwres.3 | 159 + .../bind-9.2.4rc7/lib/lwres/man/lwres.html | 447 ++ .../lib/lwres/man/lwres_buffer.3 | 279 + .../lib/lwres/man/lwres_buffer.html | 632 ++ .../lib/lwres/man/lwres_config.3 | 107 + .../lib/lwres/man/lwres_config.html | 298 + .../lib/lwres/man/lwres_context.3 | 196 + .../lib/lwres/man/lwres_context.html | 522 ++ .../bind-9.2.4rc7/lib/lwres/man/lwres_gabn.3 | 195 + .../lib/lwres/man/lwres_gabn.html | 445 ++ .../lib/lwres/man/lwres_gai_strerror.3 | 88 + .../lib/lwres/man/lwres_gai_strerror.html | 297 + .../lib/lwres/man/lwres_getaddrinfo.3 | 249 + .../lib/lwres/man/lwres_getaddrinfo.html | 725 ++ .../lib/lwres/man/lwres_gethostent.3 | 272 + .../lib/lwres/man/lwres_gethostent.html | 830 +++ .../lib/lwres/man/lwres_getipnode.3 | 189 + .../lib/lwres/man/lwres_getipnode.html | 532 ++ .../lib/lwres/man/lwres_getnameinfo.3 | 86 + .../lib/lwres/man/lwres_getnameinfo.html | 306 + .../lib/lwres/man/lwres_getrrsetbyname.3 | 144 + .../lib/lwres/man/lwres_getrrsetbyname.html | 374 + .../bind-9.2.4rc7/lib/lwres/man/lwres_gnba.3 | 188 + .../lib/lwres/man/lwres_gnba.html | 411 ++ .../lib/lwres/man/lwres_hstrerror.3 | 69 + .../lib/lwres/man/lwres_hstrerror.html | 245 + .../lib/lwres/man/lwres_inetntop.3 | 54 + .../lib/lwres/man/lwres_inetntop.html | 189 + .../bind-9.2.4rc7/lib/lwres/man/lwres_noop.3 | 162 + .../lib/lwres/man/lwres_noop.html | 412 ++ .../lib/lwres/man/lwres_packet.3 | 151 + .../lib/lwres/man/lwres_packet.html | 376 + .../lib/lwres/man/lwres_resutil.3 | 153 + .../lib/lwres/man/lwres_resutil.html | 415 ++ .../lib/lwres/unix/include/lwres/net.h | 127 + contrib/bind-9.2.4rc7/lib/lwres/version.c | 24 + contrib/bind-9.2.4rc7/version | 10 + 787 files changed, 271512 insertions(+) create mode 100644 contrib/bind-9.2.4rc7/CHANGES create mode 100644 contrib/bind-9.2.4rc7/COPYRIGHT create mode 100644 contrib/bind-9.2.4rc7/FAQ create mode 100644 contrib/bind-9.2.4rc7/Makefile.in create mode 100644 contrib/bind-9.2.4rc7/README create mode 100644 contrib/bind-9.2.4rc7/README.DELETED create mode 100644 contrib/bind-9.2.4rc7/README.DRAGONFLY create mode 100644 contrib/bind-9.2.4rc7/acconfig.h create mode 100644 contrib/bind-9.2.4rc7/bin/check/check-tool.c create mode 100644 contrib/bind-9.2.4rc7/bin/check/check-tool.h create mode 100644 contrib/bind-9.2.4rc7/bin/check/named-checkconf.8 create mode 100644 contrib/bind-9.2.4rc7/bin/check/named-checkconf.c create mode 100644 contrib/bind-9.2.4rc7/bin/check/named-checkconf.html create mode 100644 contrib/bind-9.2.4rc7/bin/check/named-checkzone.8 create mode 100644 contrib/bind-9.2.4rc7/bin/check/named-checkzone.c create mode 100644 contrib/bind-9.2.4rc7/bin/check/named-checkzone.html create mode 100644 contrib/bind-9.2.4rc7/bin/dig/dig.1 create mode 100644 contrib/bind-9.2.4rc7/bin/dig/dig.c create mode 100644 contrib/bind-9.2.4rc7/bin/dig/dig.html create mode 100644 contrib/bind-9.2.4rc7/bin/dig/dighost.c create mode 100644 contrib/bind-9.2.4rc7/bin/dig/host.1 create mode 100644 contrib/bind-9.2.4rc7/bin/dig/host.c create mode 100644 contrib/bind-9.2.4rc7/bin/dig/host.html create mode 100644 contrib/bind-9.2.4rc7/bin/dig/include/dig/dig.h create mode 100644 contrib/bind-9.2.4rc7/bin/dig/nslookup.c create mode 100644 contrib/bind-9.2.4rc7/bin/dnssec/dnssec-keygen.8 create mode 100644 contrib/bind-9.2.4rc7/bin/dnssec/dnssec-keygen.c create mode 100644 contrib/bind-9.2.4rc7/bin/dnssec/dnssec-keygen.html create mode 100644 contrib/bind-9.2.4rc7/bin/dnssec/dnssec-makekeyset.8 create mode 100644 contrib/bind-9.2.4rc7/bin/dnssec/dnssec-makekeyset.c create mode 100644 contrib/bind-9.2.4rc7/bin/dnssec/dnssec-makekeyset.html create mode 100644 contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signkey.8 create mode 100644 contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signkey.c create mode 100644 contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signkey.html create mode 100644 contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signzone.8 create mode 100644 contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signzone.c create mode 100644 contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signzone.html create mode 100644 contrib/bind-9.2.4rc7/bin/dnssec/dnssectool.c create mode 100644 contrib/bind-9.2.4rc7/bin/dnssec/dnssectool.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/aclconf.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/client.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/config.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/control.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/controlconf.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/aclconf.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/client.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/config.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/control.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/globals.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/interfacemgr.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/listenlist.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/log.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/logconf.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/lwaddr.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/lwdclient.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/lwresd.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/lwsearch.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/main.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/notify.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/query.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/server.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/sortlist.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/tkeyconf.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/tsigconf.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/types.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/update.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/xfrout.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/include/named/zoneconf.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/interfacemgr.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/listenlist.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/log.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/logconf.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/lwaddr.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/lwdclient.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/lwderror.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/lwdgabn.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/lwdgnba.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/lwdgrbn.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/lwdnoop.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/lwresd.8 create mode 100644 contrib/bind-9.2.4rc7/bin/named/lwresd.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/lwresd.html create mode 100644 contrib/bind-9.2.4rc7/bin/named/lwsearch.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/main.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/named.8 create mode 100644 contrib/bind-9.2.4rc7/bin/named/named.html create mode 100644 contrib/bind-9.2.4rc7/bin/named/notify.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/query.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/server.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/sortlist.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/tkeyconf.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/tsigconf.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/unix/include/named/os.h create mode 100644 contrib/bind-9.2.4rc7/bin/named/unix/os.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/update.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/xfrout.c create mode 100644 contrib/bind-9.2.4rc7/bin/named/zoneconf.c create mode 100644 contrib/bind-9.2.4rc7/bin/nsupdate/nsupdate.8 create mode 100644 contrib/bind-9.2.4rc7/bin/nsupdate/nsupdate.c create mode 100644 contrib/bind-9.2.4rc7/bin/nsupdate/nsupdate.html create mode 100644 contrib/bind-9.2.4rc7/bin/rndc/include/rndc/os.h create mode 100644 contrib/bind-9.2.4rc7/bin/rndc/rndc-confgen.8 create mode 100644 contrib/bind-9.2.4rc7/bin/rndc/rndc-confgen.c create mode 100644 contrib/bind-9.2.4rc7/bin/rndc/rndc-confgen.html create mode 100644 contrib/bind-9.2.4rc7/bin/rndc/rndc.8 create mode 100644 contrib/bind-9.2.4rc7/bin/rndc/rndc.c create mode 100644 contrib/bind-9.2.4rc7/bin/rndc/rndc.conf create mode 100644 contrib/bind-9.2.4rc7/bin/rndc/rndc.conf.5 create mode 100644 contrib/bind-9.2.4rc7/bin/rndc/rndc.conf.html create mode 100644 contrib/bind-9.2.4rc7/bin/rndc/rndc.html create mode 100644 contrib/bind-9.2.4rc7/bin/rndc/unix/os.c create mode 100644 contrib/bind-9.2.4rc7/bin/rndc/util.c create mode 100644 contrib/bind-9.2.4rc7/bin/rndc/util.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/README create mode 100644 contrib/bind-9.2.4rc7/lib/bind/api create mode 100644 contrib/bind-9.2.4rc7/lib/bind/bsd/daemon.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/bsd/ftruncate.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/bsd/gettimeofday.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/bsd/mktemp.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/bsd/putenv.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/bsd/readv.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/bsd/setenv.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/bsd/setitimer.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/bsd/strcasecmp.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/bsd/strdup.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/bsd/strerror.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/bsd/strpbrk.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/bsd/strsep.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/bsd/strtoul.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/bsd/utimes.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/bsd/writev.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/config.h.in create mode 100644 contrib/bind-9.2.4rc7/lib/bind/dst/dst_api.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/dst/dst_internal.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/dst/hmac_link.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/dst/md5.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/dst/md5_dgst.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/dst/md5_locl.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/dst/support.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/arpa/inet.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/arpa/nameser.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/arpa/nameser_compat.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/fd_setsize.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/hesiod.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/irp.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/irs.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/isc/assertions.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/isc/ctl.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/isc/dst.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/isc/eventlib.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/isc/heap.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/isc/irpmarshall.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/isc/list.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/isc/logging.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/isc/memcluster.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/isc/misc.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/isc/tree.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/netdb.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/netgroup.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/res_update.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/include/resolv.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/inet/inet_addr.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/inet/inet_cidr_ntop.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/inet/inet_cidr_pton.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/inet/inet_data.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/inet/inet_lnaof.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/inet/inet_makeaddr.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/inet/inet_net_ntop.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/inet/inet_net_pton.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/inet/inet_neta.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/inet/inet_netof.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/inet/inet_network.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/inet/inet_ntoa.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/inet/inet_ntop.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/inet/inet_pton.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/inet/nsap_addr.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/dns.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/dns_gr.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/dns_ho.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/dns_nw.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/dns_p.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/dns_pr.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/dns_pw.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/dns_sv.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/gai_strerror.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/gen.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/gen_gr.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/gen_ho.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/gen_ng.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/gen_nw.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/gen_p.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/gen_pr.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/gen_pw.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/gen_sv.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/getaddrinfo.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/getgrent.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/getgrent_r.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/gethostent.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/gethostent_r.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/getnameinfo.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/getnetent.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/getnetent_r.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/getnetgrent.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/getnetgrent_r.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/getprotoent.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/getprotoent_r.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/getpwent.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/getpwent_r.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/getservent.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/getservent_r.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/hesiod.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/hesiod_p.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/irp.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/irp_gr.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/irp_ho.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/irp_ng.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/irp_nw.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/irp_p.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/irp_pr.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/irp_pw.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/irp_sv.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/irpmarshall.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/irs_data.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/irs_data.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/irs_p.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/lcl.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/lcl_gr.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/lcl_ho.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/lcl_ng.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/lcl_nw.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/lcl_p.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/lcl_pr.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/lcl_pw.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/lcl_sv.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/nis.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/nis_gr.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/nis_ho.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/nis_ng.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/nis_nw.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/nis_p.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/nis_pr.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/nis_pw.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/nis_sv.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/nul_ng.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/pathnames.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/irs/util.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/assertions.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/assertions.mdoc create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/base64.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/bitncmp.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/bitncmp.mdoc create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/ctl_clnt.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/ctl_p.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/ctl_p.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/ctl_srvr.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/ev_connects.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/ev_files.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/ev_streams.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/ev_timers.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/ev_waits.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/eventlib.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/eventlib.mdoc create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/eventlib_p.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/heap.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/heap.mdoc create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/hex.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/logging.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/logging.mdoc create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/logging_p.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/memcluster.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/memcluster.mdoc create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/movefile.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/tree.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/isc/tree.mdoc create mode 100644 contrib/bind-9.2.4rc7/lib/bind/ltmain.sh create mode 100644 contrib/bind-9.2.4rc7/lib/bind/make/includes.in create mode 100644 contrib/bind-9.2.4rc7/lib/bind/make/mkdep.in create mode 100644 contrib/bind-9.2.4rc7/lib/bind/make/rules.in create mode 100644 contrib/bind-9.2.4rc7/lib/bind/mkinstalldirs create mode 100644 contrib/bind-9.2.4rc7/lib/bind/nameser/ns_date.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/nameser/ns_name.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/nameser/ns_netint.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/nameser/ns_parse.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/nameser/ns_print.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/nameser/ns_samedomain.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/nameser/ns_sign.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/nameser/ns_ttl.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/nameser/ns_verify.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/port/freebsd/include/sys/bitypes.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/port_after.h.in create mode 100644 contrib/bind-9.2.4rc7/lib/bind/port_before.h.in create mode 100644 contrib/bind-9.2.4rc7/lib/bind/resolv/herror.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/resolv/res_comp.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/resolv/res_data.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/resolv/res_debug.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/resolv/res_debug.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/resolv/res_findzonecut.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/resolv/res_init.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/resolv/res_mkquery.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/resolv/res_mkupdate.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/resolv/res_mkupdate.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/resolv/res_private.h create mode 100644 contrib/bind-9.2.4rc7/lib/bind/resolv/res_query.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/resolv/res_send.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/resolv/res_sendsigned.c create mode 100644 contrib/bind-9.2.4rc7/lib/bind/resolv/res_update.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/a6.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/acl.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/adb.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/api create mode 100644 contrib/bind-9.2.4rc7/lib/dns/byaddr.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/cache.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/callbacks.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/compress.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/db.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/dbiterator.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/dbtable.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/diff.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/dispatch.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/dnssec.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/forward.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/gen-unix.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/gen-win32.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/gen.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/a6.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/acl.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/adb.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/bit.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/byaddr.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/cache.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/callbacks.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/cert.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/compress.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/db.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/dbiterator.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/dbtable.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/diff.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/dispatch.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/dnssec.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/events.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/fixedname.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/forward.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/journal.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/keyflags.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/keytable.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/keyvalues.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/lib.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/log.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/lookup.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/master.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/masterdump.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/message.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/name.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/ncache.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/nxt.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/peer.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/rbt.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/rcode.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/rdata.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/rdataclass.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/rdatalist.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/rdataset.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/rdatasetiter.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/rdataslab.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/rdatatype.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/request.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/resolver.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/result.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/rootns.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/sdb.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/secalg.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/secproto.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/soa.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/ssu.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/stats.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/tcpmsg.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/time.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/timer.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/tkey.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/tsig.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/ttl.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/types.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/validator.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/view.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/xfrin.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/zone.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/zonekey.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/include/dns/zt.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/journal.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/keytable.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/lib.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/log.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/lookup.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/master.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/masterdump.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/message.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/name.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/ncache.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/nxt.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/peer.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rbt.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rbtdb.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rbtdb.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rbtdb64.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rbtdb64.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/any_255/tsig_250.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/any_255/tsig_250.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/afsdb_18.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/afsdb_18.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/cert_37.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/cert_37.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/cname_5.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/cname_5.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/dname_39.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/dname_39.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/gpos_27.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/gpos_27.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/hinfo_13.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/hinfo_13.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/isdn_20.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/isdn_20.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/key_25.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/key_25.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/loc_29.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/loc_29.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/mb_7.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/mb_7.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/md_3.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/md_3.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/mf_4.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/mf_4.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/mg_8.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/mg_8.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/minfo_14.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/minfo_14.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/mr_9.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/mr_9.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/mx_15.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/mx_15.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/ns_2.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/ns_2.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/null_10.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/null_10.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/nxt_30.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/nxt_30.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/opt_41.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/opt_41.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/proforma.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/proforma.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/ptr_12.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/ptr_12.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/rp_17.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/rp_17.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/rt_21.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/rt_21.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/sig_24.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/sig_24.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/soa_6.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/soa_6.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/tkey_249.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/tkey_249.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/txt_16.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/txt_16.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/unspec_103.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/unspec_103.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/x25_19.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/generic/x25_19.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/hs_4/a_1.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/hs_4/a_1.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/in_1/a6_38.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/in_1/a6_38.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/in_1/a_1.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/in_1/a_1.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/in_1/aaaa_28.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/in_1/aaaa_28.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/in_1/kx_36.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/in_1/kx_36.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/in_1/naptr_35.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/in_1/naptr_35.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/in_1/nsap-ptr_23.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/in_1/nsap-ptr_23.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/in_1/nsap_22.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/in_1/nsap_22.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/in_1/px_26.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/in_1/px_26.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/in_1/srv_33.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/in_1/srv_33.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/in_1/wks_11.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/in_1/wks_11.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/rdatastructpre.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdata/rdatastructsuf.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdatalist.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdatalist_p.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdataset.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdatasetiter.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rdataslab.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/request.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/resolver.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/result.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/rootns.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/sdb.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/sec/dst/dst_api.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/sec/dst/dst_internal.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/sec/dst/dst_lib.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/sec/dst/dst_parse.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/sec/dst/dst_parse.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/sec/dst/dst_result.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/sec/dst/gssapi_link.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/sec/dst/gssapictx.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/sec/dst/hmac_link.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/sec/dst/include/dst/dst.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/sec/dst/include/dst/gssapi.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/sec/dst/include/dst/lib.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/sec/dst/include/dst/result.h create mode 100644 contrib/bind-9.2.4rc7/lib/dns/sec/dst/key.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/sec/dst/openssl_link.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/sec/dst/openssldh_link.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/sec/dst/openssldsa_link.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/sec/dst/opensslrsa_link.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/soa.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/ssu.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/stats.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/tcpmsg.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/time.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/timer.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/tkey.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/tsig.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/ttl.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/validator.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/version.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/view.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/xfrin.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/zone.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/zonekey.c create mode 100644 contrib/bind-9.2.4rc7/lib/dns/zt.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/api create mode 100644 contrib/bind-9.2.4rc7/lib/isc/assertions.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/base64.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/bitstring.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/buffer.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/bufferlist.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/commandline.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/entropy.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/error.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/event.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/fsaccess.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/hash.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/heap.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/hex.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/hmacmd5.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/app.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/assertions.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/base64.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/bitstring.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/boolean.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/buffer.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/bufferlist.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/commandline.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/entropy.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/error.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/event.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/eventclass.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/file.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/formatcheck.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/fsaccess.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/hash.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/heap.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/hex.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/hmacmd5.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/interfaceiter.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/ipv6.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/lang.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/lex.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/lfsr.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/lib.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/list.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/log.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/magic.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/md5.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/mem.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/msgcat.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/msgs.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/mutexblock.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/netaddr.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/ondestroy.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/os.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/platform.h.in create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/print.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/quota.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/random.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/ratelimiter.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/refcount.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/region.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/resource.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/result.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/resultclass.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/rwlock.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/serial.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/sha1.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/sockaddr.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/socket.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/stdio.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/string.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/symtab.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/task.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/taskpool.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/timer.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/types.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/include/isc/util.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/inet_aton.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/inet_ntop.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/inet_pton.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/lex.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/lfsr.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/lib.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/log.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/md5.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/mem.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/mutexblock.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/netaddr.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/nls/msgcat.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/nothreads/condition.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/nothreads/include/isc/condition.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/nothreads/include/isc/mutex.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/nothreads/include/isc/once.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/nothreads/include/isc/thread.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/nothreads/mutex.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/nothreads/thread.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/ondestroy.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/print.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/pthreads/condition.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/pthreads/include/isc/condition.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/pthreads/include/isc/mutex.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/pthreads/include/isc/once.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/pthreads/include/isc/thread.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/pthreads/mutex.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/pthreads/thread.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/quota.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/random.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/ratelimiter.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/result.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/rwlock.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/serial.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/sha1.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/sockaddr.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/string.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/symtab.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/task.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/task_p.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/taskpool.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/timer.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/timer_p.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/app.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/dir.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/entropy.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/errno2result.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/errno2result.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/file.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/fsaccess.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/ifiter_ioctl.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/ifiter_sysctl.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/include/isc/dir.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/include/isc/int.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/include/isc/keyboard.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/include/isc/net.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/include/isc/netdb.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/include/isc/offset.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/include/isc/stat.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/include/isc/stdtime.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/include/isc/strerror.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/include/isc/syslog.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/include/isc/time.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/interfaceiter.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/ipv6.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/keyboard.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/net.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/os.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/resource.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/socket.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/socket_p.h create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/stdio.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/stdtime.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/strerror.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/syslog.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/unix/time.c create mode 100644 contrib/bind-9.2.4rc7/lib/isc/version.c create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/alist.c create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/api create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/base64.c create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/cc.c create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/ccmsg.c create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/include/isccc/alist.h create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/include/isccc/base64.h create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/include/isccc/cc.h create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/include/isccc/ccmsg.h create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/include/isccc/events.h create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/include/isccc/lib.h create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/include/isccc/result.h create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/include/isccc/sexpr.h create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/include/isccc/symtab.h create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/include/isccc/symtype.h create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/include/isccc/types.h create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/include/isccc/util.h create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/lib.c create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/result.c create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/sexpr.c create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/symtab.c create mode 100644 contrib/bind-9.2.4rc7/lib/isccc/version.c create mode 100644 contrib/bind-9.2.4rc7/lib/isccfg/api create mode 100644 contrib/bind-9.2.4rc7/lib/isccfg/check.c create mode 100644 contrib/bind-9.2.4rc7/lib/isccfg/include/isccfg/cfg.h create mode 100644 contrib/bind-9.2.4rc7/lib/isccfg/include/isccfg/check.h create mode 100644 contrib/bind-9.2.4rc7/lib/isccfg/include/isccfg/log.h create mode 100644 contrib/bind-9.2.4rc7/lib/isccfg/log.c create mode 100644 contrib/bind-9.2.4rc7/lib/isccfg/parser.c create mode 100644 contrib/bind-9.2.4rc7/lib/isccfg/version.c create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/api create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/assert_p.h create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/context.c create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/context_p.h create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/gai_strerror.c create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/getaddrinfo.c create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/gethost.c create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/getipnode.c create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/getnameinfo.c create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/getrrset.c create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/herror.c create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/include/lwres/context.h create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/include/lwres/int.h create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/include/lwres/ipv6.h create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/include/lwres/lang.h create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/include/lwres/list.h create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/include/lwres/lwbuffer.h create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/include/lwres/lwpacket.h create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/include/lwres/lwres.h create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/include/lwres/netdb.h.in create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/include/lwres/platform.h.in create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/include/lwres/result.h create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/lwbuffer.c create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/lwconfig.c create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/lwinetaton.c create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/lwinetntop.c create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/lwinetpton.c create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/lwpacket.c create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/lwres_gabn.c create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/lwres_gnba.c create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/lwres_grbn.c create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/lwres_noop.c create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/lwresutil.c create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres.3 create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres.html create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_buffer.3 create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_buffer.html create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_config.3 create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_config.html create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_context.3 create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_context.html create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_gabn.3 create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_gabn.html create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_gai_strerror.3 create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_gai_strerror.html create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_getaddrinfo.3 create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_getaddrinfo.html create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_gethostent.3 create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_gethostent.html create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_getipnode.3 create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_getipnode.html create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_getnameinfo.3 create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_getnameinfo.html create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_getrrsetbyname.3 create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_getrrsetbyname.html create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_gnba.3 create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_gnba.html create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_hstrerror.3 create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_hstrerror.html create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_inetntop.3 create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_inetntop.html create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_noop.3 create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_noop.html create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_packet.3 create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_packet.html create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_resutil.3 create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/man/lwres_resutil.html create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/unix/include/lwres/net.h create mode 100644 contrib/bind-9.2.4rc7/lib/lwres/version.c create mode 100644 contrib/bind-9.2.4rc7/version diff --git a/contrib/bind-9.2.4rc7/CHANGES b/contrib/bind-9.2.4rc7/CHANGES new file mode 100644 index 0000000000..6155ca94d6 --- /dev/null +++ b/contrib/bind-9.2.4rc7/CHANGES @@ -0,0 +1,4679 @@ + + --- 9.2.4rc7 released --- + +1694. [bug] Report if the builtin views of "_default" / "_bind" + are defined in named.conf. [RT #12023] + +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() macros contained a 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] + + --- 9.2.4rc6 released --- + +1685. [bug] Change #1679 loop tests weren't quite right. + +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] + +1679. [bug] When there was a single nameserver with multiple + addresses for a zone not all addresses were tried. + [RT #11706] + +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. + +1669. [bug] Restore "update forwarding denied" log messages + accidentally suppressed by change #1633. [RT# 11657] + +1660. [bug] win32: connection_reset_fix() was being called + unconditionally. [RT #11595] + + --- 9.2.4rc5 released --- + +1655. [bug] Logging multiple versions w/o a size was broken. + [RT #11446] + +1654. [bug] isc_result_totext() contained array bounds read + error. + +1650. [bug] dig, nslookup: flush standard out after each command. + +1649. [bug] Silence "unexpected non-minimal diff" message. + [RT #11206] + +1646. [bug] win32: logging file versions didn't work with + non-UNC filenames. [RT#11486] + +1644. [bug] Update the journal modification time after a + sucessfull refresh query. [RT #11436] + +1643. [bug] dns_db_closeversion() could leak memory / node + references. [RT #11163] + + --- 9.2.4rc4 released --- + +1640. [bug] win32: isc_socket_cancel(ISC_SOCKCANCEL_ACCEPT) was + incorrectly closing the socket. [RT #11291] + +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] + +1627. [bug] win32: sockets were not being closed when the + last external reference was removed. [RT# 11179] + + --- 9.2.4rc3 released --- + +1623. [bug] A serial number of zero was being displayed in the + "sending notifies" log message when also-notify was + used. [RT #11177] + +1621. [bug] match-destinations did not work for IPv6 TCP queries. + [RT# 11156] + +1619. [bug] Missing ISC_LIST_UNLINK in end_reserved_dispatches(). + [RT# 11118] + +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] + +1610. [bug] On dual stack machines "dig -b" failed to set the + address type to be looked up with "@server". + [RT #11069] + +1600. [bug] Duplicate zone pre-load checks were not case + insensitive. + +1599. [bug] Fix memory leak on error path when checking named.conf. + + --- 9.2.4rc2 released --- + +1607. [bug] dig, host and nslookup were still using random() + to generate query ids. [RT# 11013] + +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] + +1455. [bug] missing from server grammar in + doc/misc/options. [RT #5616] + +1593. [bug] rndc should return "unknown command" to unknown + commands. [RT# 10642] + + --- 9.2.4rc1 released --- + +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. + +1588. [bug] win32: TCP sockets could become blocked. [RT #10115] + +1587. [bug] dns_message_settsigkey() failed to clear existing key. + [RT #10590] + +1585. [bug] allow-v6-synthesis was not performing lookups under + IP6.INT. allow-v6-synthesis now performs a nibble + lookups under IP6.ARPA rather than a bitstring lookups. + [RT #10497] + + NOTE: allow-v6-synthesis has been deprecated. + +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] + +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] + +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] + +1568. [bug] nsupdate now reports that the update failed in + interactive mode. [RT# 10236] + +1567. [bug] 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] + +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] + +1559. [port] named should ignore SIGFSZ. + +1556. [bug] nsupdate now treats all names as fully qualified. + [RT #6427] + +1553. [bug] The windows socket code could stop accepting + connections. + +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(). + +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. [bug] Reversed timestamp sanity test on SIG. [RT #10095] + +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] + +1536. [bug] Windows socket code failed to log a error description + when returning ISC_R_UNEXPECTED. [RT #9998] + +1535. [bug] dig -x of a partial IPv4 address broken. [RT# 9949] + +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] + +1025. [bug] Don't use multicast addresses to resolve iterative + queries. [RT #101] + + --- 9.2.3 released --- + +1525. [bug] dns_cache_create() could trigger a REQUIRE + failure in isc_mem_put() during error cleanup. + +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] + +1518. [bug] dns_nxt_buildrdata(), and hence dns_nxt_build(), + contained a off-by-one error when working out the + number of octets in the bitmap. + +1514. [bug] named: isc_hash_destroy() was being called too early. + [RT #9160] + +1513. [doc] Add "US" to root-delegation-only exclude list. + + --- 9.2.3rc4 released --- + +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 subzones. + + --- 9.2.3rc3 released --- + +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(). + + --- 9.2.3rc2 released --- + +1505. [bug] Uninitialized rdataset in sdb. [RT #8750] + +1504. [func] New zone type "delegation-only". + +1503. [port] win32: install libeay32.dll outside of system32. + + --- 9.2.3rc1 released --- + +1499. [bug] isc_random need to be seeded better if arc4random() + is not used. + +1498. [port] bsdos: 5.x support. + +1497. [protocol] dig, nslookup and host now perform nibble lookups + under IP6.ARPA, use -i for IP6.INT (dig and host). + lwres now uses IP6.ARPA. + +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. [doc] A6 and "bitstring" labels are now experimental. + +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. [port] win32: port unreachables were blocking further i/o + on sockets (Windows 2000 SP2 and later). + +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] + +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. [bug] win32: we were leaking a bits in the exception + fd_set resulting in "Socket operation on non-socket" + errors from select(). [RT #2966] + +1456. [contrib] gen-data-queryperf.py from Stephane Bortzmeyer. + +1453. [doc] ARM: $GENERATE example wasn't accurate. [RT #5298] + +1452. [bug] Bad #ifdef, ISC_RFC2335 -> ISC_RFC2535. + +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. + +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. + +1439. [bug] Named could return NOERROR with certain NOTIFY + failures. Return NOTAUTH if the NOTIFY zone is + not being served. + +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. + +1437. [bug] Leave space for stdio to work in. [RT #5033] + +1434. [bug] "rndc reconfig" failed to initiate the initial + zone transfer of new slave zones. + +1431. [bug] isc_print_snprintf() "%s" with precision could walk off + end of argument. [RT #5191] + +1429. [bug] Prevent the cache getting locked to old servers. + +1424. [bug] EDNS version not being correctly printed. + +1423. [contrib] queryperf: added A6 and SRV. + +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. + +1416. [bug] Empty node should return NOERROR NODATA, not NXDOMAIN. + [RT #4715] + +1411. [bug] empty nodes should stop wildcard matches. [RT #4802] + +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. + +1401. [bug] adb wasn't clearing state when the timer expired. + +1399. [bug] Use serial number arithmetic when testing SIG + timestamps. [RT #4268] + +1397. [bug] J.ROOT-SERVERS.NET is now 192.58.128.30. + +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] + +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] + +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] + +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. + +1366. [contrib] queryperf usage was incomplete. Add '-h' for help. + +1348. [port] win32: Rewrote code to use I/O Completion Ports + in socket.c and eliminating a host of socket + errors. Performance is enhanced. + +1333. [contrib] queryperf now reports a summary of returned + rcodes (-c), rcodes are printed in mnemonic form (-v). + +1299. [bug] Set AI_ADDRCONFIG when looking up addresses + via getaddrinfo() (affects dig, host, nslookup, rndc + and nsupdate). + +1199. [doc] ARM reference to RFC 2157 should have been RFC 1918. + [RT #2436] + +1122. [tuning] Resolution timeout reduced from 90 to 30 seconds. + [RT #2046] + + 992. [doc] dig: ~/.digrc is now documented. + + --- 9.2.2 released --- + +1428. [port] hpux: temporary work around of hpux 11.11 interface + scanning. + +1427. [bug] Race condition in adb with threaded build. + +1426. [cleanup] Disable RFC2535 style DNSSEC. This is incompatible + with the forthcoming DS style DNSSEC. + +1425. [port] linux/libbind: define __USE_MISC when testing *_r() + function prototypes in netdb.h. [RT #4921] + +1395. [port] OpenSSL 0.9.7 defines CRYPTO_LOCK_ENGINE but doesn't + have a working implementation. [RT #4079] + +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. + + --- 9.2.2rc1 released --- + +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. + +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 + +1346. [bug] Win32: select timeout in socket.c was too small + as value given was meant to be milliseconds and + timeval structure requires microseconds. This + caused high CPU loads with a compute bound loop. + [RT #3358] + +1345. [port] Use a explicit -Wformat with gcc. Not all versions + include it in -Wall. + +1340. [bug] Delay and spread out the startup refresh load. + +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. + +1330. [bug] When processing events (non-threaded) only allow + the task one chance to use to use its quantum. + +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] + +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]. + +1311. [bug] lwres_getrrsetbyname leaked memory. [RT #3159] + +1310. [bug] 'rndc stop' failed to cause zones to be flushed + sometimes. [RT #3157] + +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. + +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. + +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. + +1284. [bug] The RTT estimate on unused servers was not aged. + [RT #2569] + +1282. [port] libbind: hpux 11.11 interface scanning. + +1280. [bug] libbind: escape '(' and ')' when converting to + presentation form. + +1279. [port] Darwin uses (unsigned long) for size_t. [RT #2590] + +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 . + +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. + +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. + +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. + +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] + +1248. [bug] DESTDIR was not being propagated between makes. + +1245. [bug] Treat ENOBUFS, ENOMEM and ENFILE as soft errors for + accept(). + +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] + +1209. [bug] Dig, host, nslookup were not checking the message ids + on the responses. [RT #2454] + +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. + +1089. [func] libbind: inet_{cidr,net}_{pton,ntop}() now have IPv6 + support. + + --- 9.2.1 released --- + +1251. [port] win32: a make file contained absolute version specific + references. + +1249. [bug] Missing masters clause was not handled gracefully. + [RT #2703] + +1244. [bug] Receiving a TCP message from a blackhole address would + prevent further messages being received over that + interface. + +1178. [bug] Follow and cache (if appropriate) A6 and other + data chains to completion in the additional section. + + --- 9.2.1rc2 released --- + +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] + +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] + +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] + +1218. [bug] Named incorrectly returned SERVFAIL rather than + NOTAUTH when there was a TSIG BADTIME error. [RT #2519] + +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. + +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] + +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] + + --- 9.2.1rc1 released --- + +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. + +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] + +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] Best effort parsing didn't handle packet truncation. + +1191. [bug] A dynamic update removing the last non-apex name in + a secure zone would fail. [RT #2399] + +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. + +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. + +1176. [doc] Document that allow-v6-synthesis is only performed + for clients that are supplied recursive service. + [RT #2260] + +1175. [bug] named-checkzone 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. + +1170. [bug] Don't attempt to print the token when a I/O error + occurs when parsing named.conf. [RT #2275] + +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] + +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] + +1156. [port] The configure test for strsep() incorrectly + succeeded on certain patched versions of + AIX 4.3.3. [RT #2190] + +1154. [bug] Don't attempt to obtain the netmask of a interface + if there is no address configured. [RT #2176] + +1152. [bug] libbind: read buffer overflows. + +1144. [bug] rndc-confgen would crash if both the -a and -t + options were specified. [RT #2159] + +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] + +1136. [bug] CNAME records synthesized from DNAMEs did not + have a TTL of zero as required by RFC2672. + [RT #2129] + +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] + +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] + +1081. [bug] Multicast queries were incorrectly identified + based on the source address, not the destination + address. + +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. + +1014. [bug] Some queries would cause statistics counters to + increment more than once or not at all. [RT #1321] + +1012. [bug] The -p option to named did not behave as documented. + + 988. [bug] 'additional-from-auth no;' did not work reliably + in the case of queries answered from the cache. + [RT #1436] + + 995. [bug] dig, host, nslookup: using a raw IPv6 address as a + target address should be fatal on a IPv4 only system. + + --- 9.2.0 released --- + +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] + + --- 9.2.0rc10 released --- + +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] + +1126. [bug] The server could access a freed event if shut + down while a client start event was pending + delivery. [RT #2061] + +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] + +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] + +1114. [port] Ignore more accept() errors. [RT #2021] + +1113. [bug] The allow-update-forwarding option was ignored + when specified in a view. [RT #2014] + +1111. [bug] Multi-threaded servers could deadlock processing + recursive queries due to a locking hierarchy + violation in adb.c. [RT #2017] + + --- 9.2.0rc9 released --- + +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] + +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. + +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. + +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] + +1078. [bug] We failed to correct bad tv_usec values in one case. + [RT #1966] + +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] + + --- 9.2.0rc8 released --- + +1068. [bug] errno could be overwritten by catgets(). [RT #1921] + +1066. [bug] Provide a thread safe wrapper for strerror(). + [RT #1689] + +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] + +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] + + --- 9.2.0rc7 released --- + +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] + +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] + +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. + + --- 9.2.0rc6 released --- + +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. [port] Recognize OpenUNIX 8 in config.guess. [RT #1830] + +1022. [bug] Don't report empty root hints as "extra data". + [RT #1802] + + --- 9.2.0rc5 released --- + +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] + + --- 9.2.0rc4 released --- + + +1013. [bug] It was possible to cancel a query twice when marking + a server as bogus or by having a blackhole acl. + [RT #1776] + +1010. [bug] The server could attempt to execute a command channel + command after initiating server shutdown, causing + an assertion failure. [RT #1766] + +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] + +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] + + --- 9.2.0rc3 released --- + + 990. [bug] The rndc-confgen man page was not installed. + + 989. [bug] Report filename if $INCLUDE fails for file related + errors. [RT #1736] + + 987. [bug] "dig -help" didn't show "+[no]stats". + + 986. [bug] "dig +noall" failed to clear stats and command + printing. + + 984. [bug] Multi-threading should be enabled by default on + Solaris 2.7 and newer, but it wasn't. + + --- 9.2.0rc2 released --- + + 980. [bug] Incoming zone transfers restarting after an error + could trigger an assertion failure. [RT #1692] + + 978. [bug] dns_db_attachversion() had an invalid REQUIRE() + condition. + + 977. [bug] Improve "not at top of zone" error message. + + 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] + + 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 nonrecursive. [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] + + 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] + + 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 overlimit 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 + downcased 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 maintence 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 metacharacters. 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 downcased. + + 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 unitialized 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 tranfer. + [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 sufficent 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] + + 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 + precomputation 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 + singlton 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 + inadvertantly 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. + + 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(). + + 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 signficant 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 execption 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 implememted. + + 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 recusive 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 unintialized 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 reqeust 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 rollforward 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} + + 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. [func] Add support for .digrc config file, in the + user's current directory. + + 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 recognising 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 intitialize + 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 recognises ';' 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 grammer. + + 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 reprototyped 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 commandline 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 consistancy checks from zone, + these should return as a seperate 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 advertized 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 stuctures 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 grammer 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 unitialized 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.2.4rc7/COPYRIGHT b/contrib/bind-9.2.4rc7/COPYRIGHT new file mode 100644 index 0000000000..cf55a0056c --- /dev/null +++ b/contrib/bind-9.2.4rc7/COPYRIGHT @@ -0,0 +1,30 @@ +Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +Copyright (C) 1996-2003 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: COPYRIGHT,v 1.6.2.4 2004/03/15 04:44:37 marka 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.2.4rc7/FAQ b/contrib/bind-9.2.4rc7/FAQ new file mode 100644 index 0000000000..2bb2a380b5 --- /dev/null +++ b/contrib/bind-9.2.4rc7/FAQ @@ -0,0 +1,449 @@ + + + +Frequently Asked Questions about BIND 9 + + +Q: Why doesn't -u work on Linux 2.2.x when I build with --enable-threads? + +A: Linux threads do not fully implement the Posix threads (pthreads) standard. +In particular, setuid() operates only on the current thread, not the full +process. Because of this limitation, BIND 9 cannot use setuid() on Linux as it +can on all other supported platforms. setuid() cannot be called before +creating threads, since the server does not start listening on reserved ports +until after threads have started. + + In the 2.2.18 or 2.3.99-pre3 and newer kernels, the ability to preserve +capabilities across a setuid() call is present. This allows BIND 9 to call +setuid() early, while retaining the ability to bind reserved ports. This is +a Linux-specific hack. + + On a 2.2 kernel, BIND 9 does drop many root privileges, so it should be less +of a security risk than a root process that has not dropped privileges. + + If Linux threads ever work correctly, this restriction will go away. + + Configuring BIND9 with the --disable-threads option (the default) causes a +non-threaded version to be built, which will allow -u to be used. + + +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 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. + + +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: 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 produce a usable core file from a multithreaded named on Linux? + +A: If the Linux kernel is 2.4.7 or newer, multithreaded core dumps +are usable (that is, the correct thread is dumped). Otherwise, if using +a 2.2 kernel, apply the kernel patch found in contrib/linux/coredump-patch +and rebuild the kernel. This patch will cause multithreaded programs to dump +the correct thread. + + +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 installed BIND 9 and restarted named, but it's still BIND 8. Why? + +A: BIND 9 is installed under /usr/local by default. BIND 8 is often +installed under /usr. Check that the correct named is running. + + +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 synchronized (e.g., using ntp). + + +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: I have a BIND 9 master and a BIND 8.2.3 slave, and the master is +logging error messages like "notify to 10.0.0.1#53 failed: unexpected +end of input". What's wrong? + +A: This error message is caused by a known bug in BIND 8.2.3 and is fixed +in BIND 8.2.4. It can be safely ignored - the notify has been acted on by +the slave despite the error message. + + +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: 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: 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: 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: 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: 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. + + e.g. + 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; 10.0.1/24; }; + ... + }; + view "external" { + match-clients { key external; any; }; + server 10.0.0.2 { keys external; }; + 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.0.1 { keys external; }; + recursion no; + ... + }; + + +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. + +e.g. + /etc/rc.conf + rand_irqs="3 14 15" + +See also http://people.freebsd.org/~dougb/randomness.html + + +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 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. + + e.g. + dig axfr example.com @master-server > tmp + named-checkzone example.com tmp + + +Q: I get error messages like "named.conf:99: unexpected end of input" where +99 is the last line of named.conf. + +A: Some text editors (notepad and wordpad) fail to put a line termination +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: 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 + +A: You could be generating queries faster than the slave can cope with. Lower +the serial query rate. + + serial-query-rate 5; // default 20 + +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 { !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 { 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. Forgeting 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 timzone +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 the error message "named: capset failed: Operation not permitted" +when starting named. + +A: The capset module has not been loaded into the kernel. See insmod(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 terminal can help at this + point. + + Secondly ensure that named is configured to use rndc either by + "rndc-confgen -a", rndc-confgen or manually. The Administators + 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 arguements. diff --git a/contrib/bind-9.2.4rc7/Makefile.in b/contrib/bind-9.2.4rc7/Makefile.in new file mode 100644 index 0000000000..b2a8dda70a --- /dev/null +++ b/contrib/bind-9.2.4rc7/Makefile.in @@ -0,0 +1,59 @@ +# Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 1998-2001, 2003 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: Makefile.in,v 1.41.2.3 2004/03/09 06:09:07 marka Exp $ + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_VERSION@ + +SUBDIRS = make lib bin doc @LIBBIND@ +TARGETS = + +@BIND9_MAKE_RULES@ + +distclean:: + @if [ "X@LIBBIND@" = "X" ] ; then \ + i=lib/bind; \ + echo "making $@ in `pwd`/$$i"; \ + (cd $$i; ${MAKE} ${MAKEDEFS} $@) || exit 1; \ + fi + +distclean:: + rm -f config.cache config.h config.log config.status TAGS + rm -f libtool isc-config.sh configure.lineno + rm -f util/conf.sh docutil/docbook2man-wrapper.sh + +# XXX we should clean libtool stuff too. Only do this after we add rules +# to make it. +maintainer-clean:: + rm -f configure + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${bindir} + +install:: isc-config.sh installdirs + ${INSTALL_SCRIPT} isc-config.sh ${DESTDIR}${bindir} + +tags: + rm -f TAGS + find lib bin -name "*.[ch]" -print | @ETAGS@ - + +check: test + +test: + (cd bin/tests && ${MAKE} ${MAKEDEFS} test) diff --git a/contrib/bind-9.2.4rc7/README b/contrib/bind-9.2.4rc7/README new file mode 100644 index 0000000000..2d5d7d8d1a --- /dev/null +++ b/contrib/bind-9.2.4rc7/README @@ -0,0 +1,351 @@ +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 + organisations: + + 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.2.4 + + BIND 9.2.4 is a maintenance release, containing fixes for + a number of bugs in 9.2.3. + + libbind: corresponds to that from BIND 8.4.5. + +BIND 9.2.3 + + BIND 9.2.3 is a maintenance release, containing fixes for + a number of bugs in 9.2.2. + + A new zone type delegation-only is now supported. + A new view option root-delegation-only is now supported. + + libbind: corresponds to that from BIND 8.4.0. + +BIND 9.2.2 + + BIND 9.2.2 is a maintenance release, containing fixes for + a number of bugs in 9.2.1 but no new features. RFC 2535 + style DNSSEC is disabled as it is incompatible with the + forthcoming DS style DNSSEC. + + libbind: from BIND 8.3.3. [CERT CA-2002-19] + Minimum OpenSSL version now 0.9.6e. [CERT CA-2002-23] + +BIND 9.2.1 + + BIND 9.2.1 is a maintenance release, containing fixes for + a number of bugs in 9.2.0 but no new features. + + NOTE: dig, nslookup name. now report "Not Implemented" as + NOTIMP rather than NOTIMPL. This will have impact on scripts + that are looking for NOTIMPL. + +BIND 9.2.0 + + BIND 9.2.0 introduces 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 NT/2000. + 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 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) 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 the Windows 2000 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: + + AIX 4.3 + COMPAQ Tru64 UNIX 4.0D + COMPAQ Tru64 UNIX 5 (with IPv6 EAK) + FreeBSD 3.4-STABLE, 3.5, 4.0, 4.1 + HP-UX 11.x, x < 11 + IRIX64 6.5 + NetBSD 1.5 + Red Hat Linux 6.0, 6.1, 6.2, 7.0 + Solaris 2.6, 7, 8 + Windows NT/W2K + + Additionally, we have unverified reports of success building + previous versions of BIND 9 from users of the following systems: + + AIX 5L + SuSE Linux 7.0 + Slackware Linux 7.x, 8.0 + Red Hat Linux 7.1 + Debian GNU/Linux 2.2 and 3.0 + OpenBSD 2.6, 2.8, 2.9 + UnixWare 7.1.1 + HP-UX 10.20 + BSD/OS 4.2 + OpenUNIX 8 + Mac OS X 10.1 + + 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: + -DISC_RFC2535 + Enable support RFC 2535 style DNSSEC. This + is incompatable with the upcoming DS support + and SHOULD NOT be set unless you are currently + making use of it. + + LDFLAGS + Linker flags. Defaults to empty string. + + 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, 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. + + 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). + + * gcc-3.2.1 and gcc-3.1.1 is known to cause problems with solaris-x86 + if the optimiser is enabled. Use -O0 to disable the optimiser. + * gcc ultrasparc generates incorrect code at -02. + + 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. + +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 + + Configuration questions should be sent to the BIND 9 Users + mailing list. Compilation questions should be sent to the + BIND 9 Users mailing list. + + 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/ml-archives/ + + 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.2.4rc7/README.DELETED b/contrib/bind-9.2.4rc7/README.DELETED new file mode 100644 index 0000000000..70b6c90a00 --- /dev/null +++ b/contrib/bind-9.2.4rc7/README.DELETED @@ -0,0 +1,48 @@ +bin/tests +bin/*/win32 +bin/win32 +lib/*/win32 +lib/win32 +lib/tests +lib/bind/configure* +lib/bind/port/aix32 +lib/bind/port/aix4 +lib/bind/port/bsdos* +lib/bind/port/cygwin +lib/bind/port/darwin +lib/bind/port/decunix +lib/bind/port/hpux* +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/qnx +lib/bind/port/rhapsody +lib/bind/port/sco* +lib/bind/port/solaris +lib/bind/port/sunos +lib/bind/port/ultrix +lib/bind/port/unixware* +win32utils +make +contrib +doc +docutil +*.m4 +*/*/*.m4 +config* +install-sh +isc-config.sh.in +ltmain.sh +mkinstalldirs +*/Makefile* +*/*/Makefile* +*/*/*/Makefile* +*/*/*/*/Makefile* +*/*/*/*/*/Makefile* +*/*/*/*/*/*/Makefile* +*/*/*.docbook +*/*/*/*.docbook diff --git a/contrib/bind-9.2.4rc7/README.DRAGONFLY b/contrib/bind-9.2.4rc7/README.DRAGONFLY new file mode 100644 index 0000000000..f689f606e6 --- /dev/null +++ b/contrib/bind-9.2.4rc7/README.DRAGONFLY @@ -0,0 +1,53 @@ + + BIND-9.2.4RC7 AS USED BY DRAGONFLY + + This directory contains a selected set of files from the ISC + bind-9.2.4rc7.tar.gz distribution. No files have been moved + or modified from their extracted position. + + This distribution was downloaded from the following site: + + http://www.isc.org/index.pl?/sw/bind/ + + DO NOT CREATE OR EDIT ANY FILES IN THIS DIRECTORY HIERARCHY! THIS + HIERARCHY REPRESENTS AN EXACT COPY, MINUS UNNEEDED FILES, 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/libisc + + The only additional files added to this directory are README.DRAGONFLY + and README.DELETED. + + UPGRADE PROCDURE: + + * download a new bind distribution + + * extract the archive into /usr/src/contrib, using the subdirectory + that the archive extracts as. + + * redirect the build directory to the new directory: + + /usr/src/usr.sbin/named/Makefile.inc + /usr/src/lib/libbind/Makefile + /usr/src/lib/libisc/Makefile + + * 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 CVS. + + * 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.2.4rc7/acconfig.h b/contrib/bind-9.2.4rc7/acconfig.h new file mode 100644 index 0000000000..9c578984d7 --- /dev/null +++ b/contrib/bind-9.2.4rc7/acconfig.h @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001, 2003 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: acconfig.h,v 1.35.2.8 2004/03/09 06:09:07 marka Exp $ */ + +/*** + *** This file is not to be included by any public header files, because + *** it does not get installed. + ***/ +@TOP@ + +/* define to `int' if doesn't define. */ +#undef ssize_t + +/* define on DEC OSF to enable 4.4BSD style sa_len support */ +#undef _SOCKADDR_LEN + +/* define if your system needs pthread_init() before using pthreads */ +#undef NEED_PTHREAD_INIT + +/* define if your system has sigwait() */ +#undef HAVE_SIGWAIT + +/* define if sigwait() is the UnixWare flavor */ +#undef HAVE_UNIXWARE_SIGWAIT + +/* define on Solaris to get sigwait() to work using pthreads semantics */ +#undef _POSIX_PTHREAD_SEMANTICS + +/* define if LinuxThreads is in use */ +#undef HAVE_LINUXTHREADS + +/* define if sysconf() is available */ +#undef HAVE_SYSCONF + +/* define if sysctlbyname() is available */ +#undef HAVE_SYSCTLBYNAME + +/* define if catgets() is available */ +#undef HAVE_CATGETS + +/* define if you have the NET_RT_IFLIST sysctl variable and sys/sysctl.h */ +#undef HAVE_IFLIST_SYSCTL + +/* define if chroot() is available */ +#undef HAVE_CHROOT + +/* define if tzset() is available */ +#undef HAVE_TZSET + +/* define if struct addrinfo exists */ +#undef HAVE_ADDRINFO + +/* define if getaddrinfo() exists */ +#undef HAVE_GETADDRINFO + +/* define if gai_strerror() exists */ +#undef HAVE_GAISTRERROR + +/* define if arc4random() exists */ +#undef HAVE_ARC4RANDOM + +/* define if pthread_setconcurrency() should be called to tell the + * OS how many threads we might want to run. + */ +#undef CALL_PTHREAD_SETCONCURRENCY + +/* define if IPv6 is not disabled */ +#undef WANT_IPV6 + +/* define if flockfile() is available */ +#undef HAVE_FLOCKFILE + +/* define if getc_unlocked() is available */ +#undef HAVE_GETCUNLOCKED + +/* 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 + +/* Shut up warnings about missing sigwait prototype on BSD/OS 4.0* */ +#undef SHUTUP_SIGWAIT +#ifdef SHUTUP_SIGWAIT +int sigwait(const unsigned int *set, int *sig); +#endif + +/* Shut up warnings from gcc -Wcast-qual on BSD/OS 4.1. */ +#undef SHUTUP_STDARG_CAST +#if defined(SHUTUP_STDARG_CAST) && defined(__GNUC__) +#include /* Grr. Must be included *every time*. */ +/* + * The silly continuation line is to keep configure from + * commenting out the #undef. + */ +#undef \ + va_start +#define va_start(ap, last) \ + do { \ + union { const void *konst; long *var; } _u; \ + _u.konst = &(last); \ + ap = (va_list)(_u.var + __va_words(__typeof(last))); \ + } while (0) +#endif /* SHUTUP_STDARG_CAST && __GNUC__ */ + +/* define if the system has a random number generating device */ +#undef PATH_RANDOMDEV + +/* define if pthread_attr_getstacksize() is available */ +#undef HAVE_PTHREAD_ATTR_GETSTACKSIZE + +/* define if pthread_attr_setstacksize() is available */ +#undef HAVE_PTHREAD_ATTR_SETSTACKSIZE + +/* define if you have strerror in the C library. */ +#undef HAVE_STRERROR diff --git a/contrib/bind-9.2.4rc7/bin/check/check-tool.c b/contrib/bind-9.2.4rc7/bin/check/check-tool.c new file mode 100644 index 0000000000..fda04f4ec6 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/check/check-tool.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 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: check-tool.c,v 1.4.2.1 2004/03/09 06:09:08 marka Exp $ */ + +#include + +#include + +#include "check-tool.h" +#include + +#include +#include + +isc_result_t +setup_logging(isc_mem_t *mctx, 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_setcontext(log); + + destination.file.stream = stdout; + 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); +} diff --git a/contrib/bind-9.2.4rc7/bin/check/check-tool.h b/contrib/bind-9.2.4rc7/bin/check/check-tool.h new file mode 100644 index 0000000000..3e0dfd5b55 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/check/check-tool.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 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: check-tool.h,v 1.2.2.1 2004/03/09 06:09:09 marka Exp $ */ + +#ifndef CHECK_TOOL_H +#define CHECK_TOOL_H + +#include + +#include + +ISC_LANG_BEGINDECLS + +isc_result_t +setup_logging(isc_mem_t *mctx, isc_log_t **logp); + +ISC_LANG_ENDDECLS + +#endif diff --git a/contrib/bind-9.2.4rc7/bin/check/named-checkconf.8 b/contrib/bind-9.2.4rc7/bin/check/named-checkconf.8 new file mode 100644 index 0000000000..508a149a30 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/check/named-checkconf.8 @@ -0,0 +1,52 @@ +.\" Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2000-2002 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: named-checkconf.8,v 1.11.2.2 2004/06/03 05:21:07 marka Exp $ +.\" +.TH "NAMED-CHECKCONF" "8" "June 14, 2000" "BIND9" "" +.SH NAME +named-checkconf \- named configuration file syntax checking tool +.SH SYNOPSIS +.sp +\fBnamed-checkconf\fR [ \fB-v\fR ] [ \fB-t \fIdirectory\fB\fR ] \fBfilename\fR +.SH "DESCRIPTION" +.PP +\fBnamed-checkconf\fR checks the syntax, but not +the semantics, of a named configuration file. +.SH "OPTIONS" +.TP +\fB-t \fIdirectory\fB\fR +chroot to \fIdirectory\fR so that include +directives in the configuration file are processed as if +run by a similarly chrooted named. +.TP +\fB-v\fR +Print the version of the \fBnamed-checkconf\fR +program and exit. +.TP +\fBfilename\fR +The name of the configuration file to be checked. If not +specified, it defaults to \fI/etc/named.conf\fR. +.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), +\fIBIND 9 Administrator Reference Manual\fR. +.SH "AUTHOR" +.PP +Internet Systems Consortium diff --git a/contrib/bind-9.2.4rc7/bin/check/named-checkconf.c b/contrib/bind-9.2.4rc7/bin/check/named-checkconf.c new file mode 100644 index 0000000000..83d3cd9441 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/check/named-checkconf.c @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 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: named-checkconf.c,v 1.12.2.1 2004/03/09 06:09:09 marka Exp $ */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "check-tool.h" + +isc_log_t *logc = NULL; + +static void +usage(void) { + fprintf(stderr, "usage: named-checkconf [-v] [-t directory] [named.conf]\n"); + exit(1); +} + +static isc_result_t +directory_callback(const char *clausename, cfg_obj_t *obj, void *arg) { + isc_result_t result; + 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", + directory, isc_result_totext(result)); + return (result); + } + + return (ISC_R_SUCCESS); +} + +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; + + while ((c = isc_commandline_parse(argc, argv, "t:v")) != EOF) { + switch (c) { + 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); + } + result = isc_dir_chdir("/"); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "isc_dir_chdir: %s\n", + isc_result_totext(result)); + exit(1); + } + break; + + case 'v': + printf(VERSION "\n"); + exit(0); + + default: + 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, &logc) == ISC_R_SUCCESS); + + 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 = cfg_check_namedconf(config, logc, mctx); + if (result != ISC_R_SUCCESS) + exit_status = 1; + + cfg_obj_destroy(parser, &config); + + cfg_parser_destroy(&parser); + + isc_log_destroy(&logc); + + isc_mem_destroy(&mctx); + + return (exit_status); +} diff --git a/contrib/bind-9.2.4rc7/bin/check/named-checkconf.html b/contrib/bind-9.2.4rc7/bin/check/named-checkconf.html new file mode 100644 index 0000000000..fbdc5c0a89 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/check/named-checkconf.html @@ -0,0 +1,196 @@ + + + + +named-checkconf

named-checkconf

Name

named-checkconf -- named configuration file syntax checking tool

Synopsis

named-checkconf [-v] [-t directory] {filename}

DESCRIPTION

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

OPTIONS

-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. +

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), + BIND 9 Administrator Reference Manual. +

AUTHOR

Internet Systems Consortium +

diff --git a/contrib/bind-9.2.4rc7/bin/check/named-checkzone.8 b/contrib/bind-9.2.4rc7/bin/check/named-checkzone.8 new file mode 100644 index 0000000000..a2c114b67c --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/check/named-checkzone.8 @@ -0,0 +1,65 @@ +.\" Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2000-2002 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: named-checkzone.8,v 1.11.2.3 2004/06/03 05:21:08 marka Exp $ +.\" +.TH "NAMED-CHECKZONE" "8" "June 13, 2000" "BIND9" "" +.SH NAME +named-checkzone \- zone file validity checking tool +.SH SYNOPSIS +.sp +\fBnamed-checkzone\fR [ \fB-d\fR ] [ \fB-j\fR ] [ \fB-q\fR ] [ \fB-v\fR ] [ \fB-c \fIclass\fB\fR ] \fBzonename\fR \fBfilename\fR +.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. +.SH "OPTIONS" +.TP +\fB-d\fR +Enable debugging. +.TP +\fB-q\fR +Quiet mode - exit code only. +.TP +\fB-v\fR +Print the version of the \fBnamed-checkzone\fR +program and exit. +.TP +\fB-j\fR +When loading the zone file read the journal if it exists. +.TP +\fB-c \fIclass\fB\fR +Specify the class of the zone. If not specified "IN" is assumed. +.TP +\fBzonename\fR +The domain name of the zone being checked. +.TP +\fBfilename\fR +The name of the zone file. +.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), +\fIRFC 1035\fR, +\fIBIND 9 Administrator Reference Manual\fR. +.SH "AUTHOR" +.PP +Internet Systems Consortium diff --git a/contrib/bind-9.2.4rc7/bin/check/named-checkzone.c b/contrib/bind-9.2.4rc7/bin/check/named-checkzone.c new file mode 100644 index 0000000000..d92b86aefe --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/check/named-checkzone.c @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2002 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: named-checkzone.c,v 1.13.2.4 2004/03/09 06:09:09 marka Exp $ */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "check-tool.h" + +static int debug = 0; +isc_boolean_t nomerge = ISC_TRUE; +static int quiet = 0; +static isc_mem_t *mctx = NULL; +dns_zone_t *zone = NULL; +dns_zonetype_t zonetype = dns_zone_master; +static const char *dbtype[] = { "rbt" }; + +#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: named-checkzone [-djqv] [-c class] zonename filename \n"); + exit(1); +} + +static isc_result_t +setup(char *zonename, char *filename, char *classname) { + isc_result_t result; + dns_rdataclass_t rdclass; + isc_textregion_t region; + isc_buffer_t buffer; + dns_fixedname_t fixorigin; + dns_name_t *origin; + + if (debug) + fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n", + zonename, filename, classname); + result = dns_zone_create(&zone, mctx); + ERRRET(result, "dns_zone_new"); + + dns_zone_settype(zone, zonetype); + + isc_buffer_init(&buffer, zonename, strlen(zonename)); + isc_buffer_add(&buffer, strlen(zonename)); + dns_fixedname_init(&fixorigin); + result = dns_name_fromtext(dns_fixedname_name(&fixorigin), + &buffer, dns_rootname, ISC_FALSE, NULL); + ERRRET(result, "dns_name_fromtext"); + origin = dns_fixedname_name(&fixorigin); + + result = dns_zone_setorigin(zone, origin); + ERRRET(result, "dns_zone_setorigin"); + + result = dns_zone_setdbtype(zone, 1, (const char * const *) dbtype); + ERRRET(result, "dns_zone_setdatabase"); + + result = dns_zone_setfile(zone, filename); + ERRRET(result, "dns_zone_setdatabase"); + + region.base = classname; + region.length = strlen(classname); + result = dns_rdataclass_fromtext(&rdclass, ®ion); + ERRRET(result, "dns_rdataclass_fromtext"); + + dns_zone_setclass(zone, rdclass); + dns_zone_setoption(zone, DNS_ZONEOPT_MANYERRORS, ISC_TRUE); + dns_zone_setoption(zone, DNS_ZONEOPT_NOMERGE, nomerge); + + result = dns_zone_load(zone); + + return (result); +} + +static void +destroy(void) { + if (zone != NULL) + dns_zone_detach(&zone); +} + +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; + + while ((c = isc_commandline_parse(argc, argv, "c:djqsv")) != EOF) { + switch (c) { + case 'c': + classname = isc_commandline_argument; + break; + case 'd': + debug++; + break; + + case 'j': + nomerge = ISC_FALSE; + break; + case 'q': + quiet++; + break; + case 'v': + printf(VERSION "\n"); + exit(0); + default: + usage(); + } + } + + 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, &lctx) == ISC_R_SUCCESS); + dns_log_init(lctx); + dns_log_setcontext(lctx); + } + + dns_result_register(); + + origin = argv[isc_commandline_index++]; + filename = argv[isc_commandline_index++]; + result = setup(origin, filename, classname); + if (!quiet && result == ISC_R_SUCCESS) + fprintf(stdout, "OK\n"); + destroy(); + if (lctx != NULL) + isc_log_destroy(&lctx); + isc_mem_destroy(&mctx); + return ((result == ISC_R_SUCCESS) ? 0 : 1); +} diff --git a/contrib/bind-9.2.4rc7/bin/check/named-checkzone.html b/contrib/bind-9.2.4rc7/bin/check/named-checkzone.html new file mode 100644 index 0000000000..de0eeb4ea2 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/check/named-checkzone.html @@ -0,0 +1,237 @@ + + + + +named-checkzone

named-checkzone

Name

named-checkzone -- zone file validity checking tool

Synopsis

named-checkzone [-d] [-j] [-q] [-v] [-c class] {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. +

OPTIONS

-d

Enable debugging. +

-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. +

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), + RFC 1035, + BIND 9 Administrator Reference Manual. +

AUTHOR

Internet Systems Consortium +

diff --git a/contrib/bind-9.2.4rc7/bin/dig/dig.1 b/contrib/bind-9.2.4rc7/bin/dig/dig.1 new file mode 100644 index 0000000000..1e919dcfee --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dig/dig.1 @@ -0,0 +1,370 @@ +.\" Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2000, 2001, 2003 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: dig.1,v 1.14.2.5 2004/03/15 04:44:38 marka Exp $ +.\" +.TH "DIG" "1" "Jun 30, 2000" "BIND9" "" +.SH NAME +dig \- DNS lookup utility +.SH SYNOPSIS +.sp +\fBdig\fR [ \fB@server\fR ] [ \fB-b \fIaddress\fB\fR ] [ \fB-c \fIclass\fB\fR ] [ \fB-f \fIfilename\fB\fR ] [ \fB-k \fIfilename\fB\fR ] [ \fB-p \fIport#\fB\fR ] [ \fB-t \fItype\fB\fR ] [ \fB-x \fIaddr\fB\fR ] [ \fB-y \fIname:key\fB\fR ] [ \fBname\fR ] [ \fBtype\fR ] [ \fBclass\fR ] [ \fBqueryopt\fR\fI...\fR ] +.sp +\fBdig\fR [ \fB-h\fR ] +.sp +\fBdig\fR [ \fBglobal-queryopt\fR\fI...\fR ] [ \fBquery\fR\fI...\fR ] +.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 BIND9 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, 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 arguements. +.SH "SIMPLE USAGE" +.PP +A typical invocation of \fBdig\fR looks like: +.sp +.nf + dig @server name type +.sp +.fi +where: +.TP +\fBserver\fR +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. +.TP +\fBname\fR +is the name of the resource record that is to be looked up. +.TP +\fBtype\fR +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. +.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. +.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 organised in +the same way they would be presented as queries to +\fBdig\fR using the command-line interface. +.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-t\fR option sets the query type to +\fItype\fR. It can be any valid query type which is +supported in BIND9. The default query type "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 +Reverse lookups - mapping addresses to names - 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 the IP6.ARPA domain and binary labels as defined in +RFC2874. To use the older RFC1886 method using the IP6.INT domain and +"nibble" labels, specify the \fB-n\fR (nibble) option. +.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; +\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: +.TP +\fB+[no]tcp\fR +Use [do not use] TCP when querying name servers. The default +behaviour is to use UDP unless an AXFR or IXFR query is requested, in +which case a TCP connection is used. +.TP +\fB+[no]vc\fR +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". +.TP +\fB+[no]ignore\fR +Ignore truncation in UDP responses instead of retrying with TCP. By +default, TCP retries are performed. +.TP +\fB+domain=somename\fR +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. +.TP +\fB+[no]search\fR +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. +.TP +\fB+[no]defname\fR +Deprecated, treated as a synonym for \fI+[no]search\fR +.TP +\fB+[no]aaonly\fR +This option does nothing. It is provided for compatibility with old +versions of \fBdig\fR where it set an unimplemented +resolver flag. +.TP +\fB+[no]adflag\fR +Set [do not set] the AD (authentic data) bit in the query. The AD bit +currently has a standard meaning only in responses, not in queries, +but the ability to set the bit in the query is provided for +completeness. +.TP +\fB+[no]cdflag\fR +Set [do not set] the CD (checking disabled) bit in the query. This +requests the server to not perform DNSSEC validation of responses. +.TP +\fB+[no]recurse\fR +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. +.TP +\fB+[no]nssearch\fR +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. +.TP +\fB+[no]trace\fR +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. +.TP +\fB+[no]cmd\fR +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. +.TP +\fB+[no]short\fR +Provide a terse answer. The default is to print the answer in a +verbose form. +.TP +\fB+[no]identify\fR +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. +.TP +\fB+[no]comments\fR +Toggle the display of comment lines in the output. The default is to +print comments. +.TP +\fB+[no]stats\fR +This query option toggles the printing of statistics: when the query +was made, the size of the reply and so on. The default behaviour is +to print the query statistics. +.TP +\fB+[no]qr\fR +Print [do not print] the query as it is sent. +By default, the query is not printed. +.TP +\fB+[no]question\fR +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. +.TP +\fB+[no]answer\fR +Display [do not display] the answer section of a reply. The default +is to display it. +.TP +\fB+[no]authority\fR +Display [do not display] the authority section of a reply. The +default is to display it. +.TP +\fB+[no]additional\fR +Display [do not display] the additional section of a reply. +The default is to display it. +.TP +\fB+[no]all\fR +Set or clear all display flags. +.TP +\fB+time=T\fR +Sets the timeout for a query to +\fIT\fR seconds. The default time out is 5 seconds. +An attempt to set \fIT\fR to less than 1 will result +in a query timeout of 1 second being applied. +.TP +\fB+tries=T\fR +Sets the number of times to retry 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 +retries is silently rounded up to 1. +.TP +\fB+ndots=D\fR +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. +.TP +\fB+bufsize=B\fR +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. +.TP +\fB+[no]multiline\fR +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. +.TP +\fB+[no]fail\fR +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 +behaviour. +.TP +\fB+[no]besteffort\fR +Attempt to display the contents of messages which are malformed. +The default is to not display malformed answers. +.TP +\fB+[no]dnssec\fR +Requests DNSSEC records be sent by setting the DNSSEC OK bit (DO) +in the OPT record in the additional section of the query. +.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 +.nf +dig +qr www.isc.org any -x 127.0.0.1 isc.org ns +noqr +.sp +.fi +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 "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), +\fIRFC1035\fR. +.SH "BUGS" +.PP +There are probably too many query options. diff --git a/contrib/bind-9.2.4rc7/bin/dig/dig.c b/contrib/bind-9.2.4rc7/bin/dig/dig.c new file mode 100644 index 0000000000..b401dc72ab --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dig/dig.c @@ -0,0 +1,1409 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2003 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: dig.c,v 1.157.2.16 2004/06/07 03:59:08 marka Exp $ */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +extern ISC_LIST(dig_lookup_t) lookup_list; +extern dig_serverlist_t server_list; +extern ISC_LIST(dig_searchlist_t) search_list; + +#define ADD_STRING(b, s) { \ + if (strlen(s) >= isc_buffer_availablelength(b)) \ + return (ISC_R_NOSPACE); \ + else \ + isc_buffer_putstr(b, s); \ +} + + +extern isc_boolean_t have_ipv4, have_ipv6, specified_source, + usesearch, 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 tries; +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_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; +dig_lookup_t *default_lookup = NULL; + +extern isc_boolean_t debugging, memdebugging; +static char *batchname = NULL; +static FILE *batchfp = NULL; +static char *argv0; + +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; + +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" +}; + +extern char *progname; + +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); +} + +static void +help(void) { + print_usage(stdout); + fputs( +"Where: domain are 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 in-addr lookups)\n" +" -i (IP6.INT reverse IPv6 lookups)\n" +" -f filename (batch mode)\n" +" -b address (bind to source address)\n" +" -p port (specify port number)\n" +" -t type (specify query type)\n" +" -c class (specify query class)\n" +" -k keyfile (specify tsig key file)\n" +" -y name:key (specify named base64 tsig key)\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" +" +domain=### (Set default domainname)\n" +" +bufsize=### (Set EDNS0 Max UDP packet size)\n" +" +ndots=### (Set NDOTS value)\n" +" +[no]search (Set whether to use searchlist)\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)\n" +" +[no]adflag (Set AD flag in query)\n" +" +[no]cdflag (Set CD flag in query)\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]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]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", + 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; + isc_result_t result; + time_t tnow; + char fromtext[ISC_SOCKADDR_FORMATSIZE]; + + isc_sockaddr_format(from, fromtext, sizeof(fromtext)); + + result = isc_time_now(&now); + check_result(result, "isc_time_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: %d records\n", + query->rr_count); + } else { + printf(";; MSG SIZE rcvd: %d\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 %u bytes from %s(%s) in %d ms\n\n", + 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) { + result = isc_time_now(&now); + if (result != ISC_R_SUCCESS) + return (result); + 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); +} + +/* + * 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; + const dns_master_style_t *style; + + if (multiline) + style = &dns_master_style_default; + else + style = &dns_master_style_debug; + + 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], rcodetext[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]); + } + } + +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 + return (result); + } + 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); + 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) { + 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); + } + } +} + +/* + * Reorder an argument list so that server names all come at the end. + * This is a bit of a hack, to allow batch-mode processing to properly + * handle the server options. + */ +static void +reorder_args(int argc, char *argv[]) { + int i, j; + char *ptr; + int end; + + debug("reorder_args()"); + end = argc - 1; + while (argv[end][0] == '@') { + end--; + if (end == 0) + return; + } + debug("arg[end]=%s", argv[end]); + for (i = 1; i < end - 1; i++) { + if (argv[i][0] == '@') { + debug("arg[%d]=%s", i, argv[i]); + ptr = argv[i]; + for (j = i + 1; j < end; j++) { + debug("Moving %s to %d", argv[j], j - 1); + argv[j - 1] = argv[j]; + } + debug("moving %s to end, %d", ptr, end - 1); + argv[end - 1] = ptr; + end--; + if (end < 1) + return; + } + } +} + +static isc_uint32_t +parse_uint(char *arg, const char *desc, isc_uint32_t max) { + char *endp; + isc_uint32_t tmp; + + tmp = strtoul(arg, &endp, 10); + if (*endp != '\0') + fatal("%s '%s' must be numeric", desc, arg); + if (tmp > max) + fatal("%s '%s' out of range", desc, arg); + 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; + + 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; + } + switch (cmd[0]) { + case 'a': + switch (cmd[1]) { + case 'a': /* aaflag */ + lookup->aaonly = state; + break; + case 'd': + switch (cmd[2]) { + case 'd': /* additional */ + lookup->section_additional = state; + break; + case 'f': /* adflag */ + lookup->adflag = state; + break; + default: + goto invalid_option; + } + break; + case 'l': /* 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 */ + lookup->section_answer = state; + break; + case 'u': /* authority */ + lookup->section_authority = state; + break; + default: + goto invalid_option; + } + break; + case 'b': + switch (cmd[1]) { + case 'e':/* besteffort */ + lookup->besteffort = state; + break; + case 'u':/* 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 */ + lookup->cdflag = state; + break; + case 'm': /* cmd */ + printcmd = state; + break; + case 'o': /* comments */ + lookup->comments = state; + if (lookup == default_lookup) + pluscomm = state; + break; + default: + goto invalid_option; + } + break; + case 'd': + switch (cmd[1]) { + case 'e': /* defname */ + usesearch = state; + break; + case 'n': /* dnssec */ + lookup->dnssec = state; + break; + case 'o': /* 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 'f': /* fail */ + lookup->servfail_stops = state; + break; + case 'i': + switch (cmd[1]) { + case 'd': /* identify */ + lookup->identify = state; + break; + case 'g': /* ignore */ + default: /* Inherets default for compatibility */ + lookup->ignore = ISC_TRUE; + } + break; + case 'm': /* multiline */ + multiline = state; + break; + case 'n': + switch (cmd[1]) { + case 'd': /* ndots */ + if (value == NULL) + goto need_value; + if (!state) + goto invalid_option; + ndots = parse_uint(value, "ndots", MAXNDOTS); + break; + case 's': /* nssearch */ + lookup->ns_search_only = state; + if (state) { + lookup->trace_root = ISC_TRUE; + lookup->recurse = ISC_FALSE; + 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; + case 'q': + switch (cmd[1]) { + case 'r': /* qr */ + qr = state; + break; + case 'u': /* question */ + lookup->section_question = state; + if (lookup == default_lookup) + plusquest = state; + break; + default: + goto invalid_option; + } + break; + case 'r': /* recurse */ + lookup->recurse = state; + break; + case 's': + switch (cmd[1]) { + case 'e': /* search */ + usesearch = state; + break; + case 'h': /* 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 't': /* stats */ + lookup->stats = state; + break; + default: + goto invalid_option; + } + break; + case 't': + switch (cmd[1]) { + case 'c': /* tcp */ + if (!is_batchfile) + lookup->tcp_mode = state; + break; + case 'i': /* timeout */ + if (value == NULL) + goto need_value; + if (!state) + goto invalid_option; + timeout = parse_uint(value, "timeout", MAXTIMEOUT); + if (timeout == 0) + timeout = 1; + break; + case 'r': + switch (cmd[2]) { + case 'a': /* 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; + } + break; + case 'i': /* tries */ + if (value == NULL) + goto need_value; + if (!state) + goto invalid_option; + lookup->retries = parse_uint(value, "retries", + MAXTRIES); + if (lookup->retries == 0) + lookup->retries = 1; + break; + default: + goto invalid_option; + } + break; + default: + goto invalid_option; + } + break; + case 'v': + 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 isc_boolean_t +dash_option(char *option, char *next, dig_lookup_t **lookup, + isc_boolean_t *open_type_class, + isc_boolean_t *firstarg, + int argc, char **argv) +{ + char cmd, *value, *ptr; + 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; + + cmd = option[0]; + if (strlen(option) > 1U) { + value_from_next = ISC_FALSE; + value = &option[1]; + } else { + value_from_next = ISC_TRUE; + value = next; + } + switch (cmd) { + case 'd': + debugging = ISC_TRUE; + return (ISC_FALSE); + case 'h': + help(); + exit(0); + break; + case 'i': + ip6_int = ISC_TRUE; + return (ISC_FALSE); + case 'm': /* memdebug */ + /* memdebug is handled in preparse_args() */ + return (ISC_FALSE); + case 'n': + /* deprecated */ + return (ISC_FALSE); + } + if (value == NULL) + goto invalid_option; + switch (cmd) { + case 'b': + if (have_ipv6 && inet_pton(AF_INET6, value, &in6) == 1) + isc_sockaddr_fromin6(&bind_address, &in6, 0); + else if (have_ipv4 && inet_pton(AF_INET, value, &in4) == 1) + isc_sockaddr_fromin(&bind_address, &in4, 0); + else + fatal("invalid address %s", value); + 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 '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; + } 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,":"); + if (ptr == NULL) { + usage(); + } + strncpy(keynametext, ptr, sizeof(keynametext)); + keynametext[sizeof(keynametext)-1]=0; + ptr = next_token(&value, ""); + if (ptr == NULL) + usage(); + strncpy(keysecret, ptr, sizeof(keysecret)); + keysecret[sizeof(keysecret)-1]=0; + return (value_from_next); + case 'x': + *lookup = clone_lookup(default_lookup, ISC_TRUE); + if (get_reverse(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 (*lookup && *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; + + rc = argc; + rv = argv; + for (rc--, rv++; rc > 0; rc--, rv++) { + if (strcmp(rv[0], "-m") == 0) { + memdebugging = ISC_TRUE; + isc_mem_debugging = ISC_MEM_DEBUGTRACE | + ISC_MEM_DEBUGRECORD; + return; + } + } +} + + +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_server_t *srv = NULL; + 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; + + /* + * 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 .digrc as a special batchfile + */ + homedir = getenv("HOME"); + if (homedir != NULL) + snprintf(rcfile, sizeof(rcfile), "%s/.digrc", homedir); + else + strcpy(rcfile, ".digrc"); + 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]; + + reorder_args(bargc, (char **)bargv); + parse_args(ISC_TRUE, ISC_TRUE, bargc, + (char **)bargv); + } + fclose(batchfp); + } +#endif + } + + 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) { + srv = make_server(&rv[0][1]); + ISC_LIST_APPEND(lookup->my_server_list, + srv, link); + } 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, + &firstarg, argc, argv)) { + rc--; + rv++; + } + } else { + if (dash_option(&rv[0][1], rv[1], + &lookup, &open_type_class, + &firstarg, argc, argv)) { + rc--; + rv++; + } + } + } else { + /* + * Anything which isn't an option + */ + if (open_type_class) { + if (strncmp(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; + } 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) { + lookup = clone_lookup(default_lookup, + ISC_TRUE); + if (firstarg) { + printgreeting(argc, argv, lookup); + firstarg = ISC_FALSE; + } + 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; + 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]; + + reorder_args(bargc, (char **)bargv); + parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv); + } + } + /* + * If no lookup specified, search for root + */ + if ((lookup_list.head == NULL) && !config_only) { + lookup = clone_lookup(default_lookup, 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); + } +} + +/* + * Callback from dighost.c to allow program-specific shutdown code. Here, + * 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; + + + 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; + + reorder_args(bargc, (char **)bargv); + parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv); + start_lookup(); + } else { + batchname = NULL; + if (batchfp != stdin) + fclose(batchfp); + isc_app_shutdown(); + return; + } +} + +int +main(int argc, char **argv) { + isc_result_t result; + dig_server_t *s, *s2; + + 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(); + s = ISC_LIST_HEAD(default_lookup->my_server_list); + while (s != NULL) { + debug("freeing server %p belonging to %p", + s, default_lookup); + s2 = s; + s = ISC_LIST_NEXT(s, link); + ISC_LIST_DEQUEUE(default_lookup->my_server_list, s2, link); + isc_mem_free(mctx, s2); + } + isc_mem_free(mctx, default_lookup); + if (batchname != NULL) { + if (batchfp != stdin) + fclose(batchfp); + batchname = NULL; + } + cancel_all(); + destroy_libs(); + isc_app_finish(); + return (exitcode); +} diff --git a/contrib/bind-9.2.4rc7/bin/dig/dig.html b/contrib/bind-9.2.4rc7/bin/dig/dig.html new file mode 100644 index 0000000000..c8110dbd3e --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dig/dig.html @@ -0,0 +1,1158 @@ + + + + +dig

dig

Name

dig -- DNS lookup utility

Synopsis

dig [@server] [-b address] [-c class] [-f filename] [-k filename] [-p port#] [-t type] [-x addr] [-y name:key] [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 BIND9 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, 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 arguements.

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.

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 organised in +the same way they would be presented as queries to +dig using the command-line interface.

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 -t option sets the query type to +type. It can be any valid query type which is +supported in BIND9. The default query type "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.

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 the IP6.ARPA domain and binary labels as defined in +RFC2874. To use the older RFC1886 method using the IP6.INT domain and +"nibble" labels, specify the -n (nibble) option.

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; +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 +behaviour 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]defname

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

+[no]aaonly

This option does nothing. It is provided for compatibility with old +versions of dig where it set an unimplemented +resolver flag.

+[no]adflag

Set [do not set] the AD (authentic data) bit in the query. The AD bit +currently has a standard meaning only in responses, not in queries, +but the ability to set the bit in the query is provided for +completeness.

+[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]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 behaviour 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 time out 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 retry UDP queries to server to +T instead of the default, 3. If +T is less than or equal to zero, the number of +retries is silently rounded up to 1.

+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.

+[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 +behaviour.

+[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.

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.

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.2.4rc7/bin/dig/dighost.c b/contrib/bind-9.2.4rc7/bin/dig/dighost.c new file mode 100644 index 0000000000..301a4649dc --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dig/dighost.c @@ -0,0 +1,2723 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2003 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: dighost.c,v 1.221.2.22 2004/04/15 06:53:18 marka Exp $ */ + +/* + * 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 + +#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_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 + +ISC_LIST(dig_lookup_t) lookup_list; +dig_serverlist_t server_list; +ISC_LIST(dig_searchlist_t) search_list; + +isc_boolean_t + have_ipv4 = ISC_FALSE, + have_ipv6 = ISC_FALSE, + specified_source = ISC_FALSE, + free_now = ISC_FALSE, + cancel_now = ISC_FALSE, + usesearch = ISC_FALSE, + qr = ISC_FALSE, + is_dst_up = ISC_FALSE; +in_port_t port = 53; +unsigned int timeout = 0; +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 = 2; +int lookup_counter = 0; + +/* + * Exit Codes: + * 0 Everything went well, including things like NXDOMAIN + * 1 Usage error + * 7 Got too many RR's or Names + * 8 Couldn't open batch file + * 9 No reply from server + * 10 Internal error + */ +int exitcode = 0; +int fatalexit = 0; +char keynametext[MXNAME]; +char keyfile[MXNAME] = ""; +char keysecret[MXNAME] = ""; +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; + +/* + * 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 +connect_timeout(isc_task_t *task, isc_event_t *event); + +static void +launch_next_query(dig_query_t *query, isc_boolean_t include_question); + +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, 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 = DNS_BYADDROPT_IPV6NIBBLE; + + 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, MXNAME); + 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 + MXNAME; + 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; + + 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) { + 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) { + 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); + srv->servername[MXNAME-1] = 0; + ISC_LINK_INIT(srv, link); + return (srv); +} + +/* + * 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); + 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->udpsize = 0; + 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; + 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 seperately 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); + 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->udpsize = lookold->udpsize; + 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; + + 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, dns_tsig_hmacmd5_name, + 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)); + + 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, + mctx, &dstkey); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "Couldn't read key from %s: %s\n", + keyfile, isc_result_totext(result)); + goto failure; + } + + result = dns_tsigkey_createfromkey(dst_key_name(dstkey), + dns_tsig_hmacmd5_name, + 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); +} + +/* + * Setup the system as a whole, reading key information and resolv.conf + * settings. + */ +void +setup_system(void) { + char rcinput[MXNAME]; + FILE *fp; + char *ptr; + dig_server_t *srv; + dig_searchlist_t *search, *domain = NULL; + isc_boolean_t get_servers; + char *input; + + debug("setup_system()"); + + free_now = ISC_FALSE; + get_servers = ISC_TF(server_list.head == NULL); + fp = fopen(RESOLV_CONF, "r"); + /* XXX Use lwres resolv.conf reader */ + if (fp == NULL) + goto no_file; + + while (fgets(rcinput, MXNAME, fp) != 0) { + input = rcinput; + ptr = next_token(&input, " \t\r\n"); + if (ptr != NULL) { + if (get_servers && + strcasecmp(ptr, "nameserver") == 0) { + debug("got a nameserver line"); + ptr = next_token(&input, " \t\r\n"); + if (ptr != NULL) { + srv = make_server(ptr); + ISC_LIST_APPEND(server_list, srv, link); + } + } else if (strcasecmp(ptr, "options") == 0) { + ptr = next_token(&input, " \t\r\n"); + if (ptr != NULL) { + if (strncasecmp(ptr, "ndots:", 6) == 0 + && ndots == -1) + { + ndots = atoi(&ptr[6]); + debug("ndots is %d.", ndots); + } + } + } else if (strcasecmp(ptr, "search") == 0){ + while ((ptr = next_token(&input, " \t\r\n")) + != NULL) { + debug("adding search %s", ptr); + search = make_searchlist_entry(ptr); + ISC_LIST_INITANDAPPEND(search_list, + search, link); + } + } else if (strcasecmp(ptr, "domain") == 0) { + while ((ptr = next_token(&input, " \t\r\n")) + != NULL) { + if (domain != NULL) + isc_mem_free(mctx, domain); + domain = make_searchlist_entry(ptr); + } + } + } + } + fclose(fp); + no_file: + + if (ISC_LIST_EMPTY(search_list) && domain != NULL) { + ISC_LIST_INITANDAPPEND(search_list, domain, link); + domain = NULL; + } + if (domain != NULL) + isc_mem_free(mctx, domain); + + if (ndots == -1) + ndots = 1; + + if (server_list.head == NULL) { + srv = make_server("127.0.0.1"); + ISC_LIST_APPEND(server_list, srv, link); + } + + if (keyfile[0] != 0) + setup_file_key(); + else if (keysecret[0] != 0) + setup_text_key(); +} + +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 and the DO bit. + */ +static void +add_opt(dns_message_t *msg, isc_uint16_t udpsize, isc_boolean_t dnssec) { + 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 = 0; + if (dnssec) + rdatalist->ttl = DNS_MESSAGEEXTFLAG_DO; + 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); + 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_server_t *s; + dig_query_t *q; + void *ptr; + + 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. + */ + debug("cleared"); + 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); + return (ISC_TRUE); +} + + +/* + * 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); + 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; + + 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); + + rdataset = NULL; + result = dns_message_findtype(name, dns_rdatatype_ns, 0, + &rdataset); + if (result != ISC_R_SUCCESS) + continue; + + debug("found NS set"); + + 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++; + (void)dns_rdata_tostruct(&rdata, &ns, NULL); + 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; + } + srv = make_server(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)); + + 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; + + 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) + /* + * Then we just did rootorg; there's nothing left. + */ + return (ISC_FALSE); + lookup = requeue_lookup(query->lookup, ISC_TRUE); + lookup->origin = ISC_LIST_NEXT(query->lookup->origin, link); + 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]; + + 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)); + + /* + * 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. + */ + /* XXX New search here? */ + if ((count_dots(lookup->textname) >= ndots) || !usesearch) + lookup->origin = NULL; /* Force abs lookup */ + else if (lookup->origin == NULL && lookup->new_search && usesearch) { + lookup->origin = ISC_LIST_HEAD(search_list); + } + 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 { + debug("using root origin"); + 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, + dns_rootname, + ISC_FALSE, + &lookup->namebuf); + } + 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)) { + lookup->doing_xfr = ISC_TRUE; + /* + * Force TCP mode if we're doing an xfr. + * XXX UDP ixfr's would be useful + */ + lookup->tcp_mode = 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->sendbuf, lookup->sendspace, COMMSIZE); + result = dns_message_renderbegin(lookup->sendmsg, &cctx, + &lookup->sendbuf); + check_result(result, "dns_message_renderbegin"); + if (lookup->udpsize > 0 || lookup->dnssec) { + if (lookup->udpsize == 0) + lookup->udpsize = 2048; + add_opt(lookup->sendmsg, lookup->udpsize, lookup->dnssec); + } + + 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->sendbuf) > 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->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->rr_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); + + ISC_LINK_INIT(query, link); + ISC_LIST_ENQUEUE(lookup->q, query, link); + } + /* XXX qrflag, print_query, etc... */ + if (!ISC_LIST_EMPTY(lookup->q) && qr) { + 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) { + REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE); + + UNUSED(_task); + + LOCK_LOOKUP; + + isc_event_free(&event); + + debug("send_done()"); + sendcount--; + debug("sendcount=%d", sendcount); + INSIST(sendcount >= 0); + 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 +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; + get_address(query->servname, port, &query->sockaddr); + + 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); + 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); + } + 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; + dig_query_t *next; + 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; + get_address(query->servname, port, &query->sockaddr); + + 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); + } else { + isc_sockaddr_anyofpf(&bind_any, + isc_sockaddr_pf(&query->sockaddr)); + result = isc_socket_bind(query->sock, &bind_any); + } + 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_LINK_INIT(&l->sendbuf, link); + ISC_LIST_ENQUEUE(query->sendlist, &l->sendbuf, + link); + debug("sending a request"); + result = isc_time_now(&query->time_sent); + check_result(result, "isc_time_now"); + INSIST(query->sock != NULL); + result = isc_socket_sendtov(query->sock, &query->sendlist, + global_task, send_done, query, + &query->sockaddr, NULL); + check_result(result, "isc_socket_sendtov"); + sendcount++; + /* + * 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_udp(next); + } +} + +/* + * 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, *n; + 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 + 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--; + n = 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); + + 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; + } + b = ISC_LIST_HEAD(sevent->bufferlist); + ISC_LIST_DEQUEUE(sevent->bufferlist, &query->lengthbuf, link); + 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->lookup->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_LINK_INIT(&query->lookup->sendbuf, link); + ISC_LIST_ENQUEUE(query->sendlist, &query->lookup->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"); + result = isc_time_now(&query->time_sent); + check_result(result, "isc_time_now"); + 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. + */ + + 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"); + (void)dns_rdata_tostruct(&rdata, &soa, NULL); + 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; + 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; + + 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; + + 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; + } + + b = ISC_LIST_HEAD(sevent->bufferlist); + ISC_LIST_DEQUEUE(sevent->bufferlist, &query->recvbuf, link); + + if (!l->tcp_mode && + !isc_sockaddr_equal(&sevent->address, &query->sockaddr)) { + 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 (!match) { + 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; + } + + 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; + 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->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) { + 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)) { + printf(";; Got SERVFAIL reply from %s, " + "trying next server\n", + 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"); + } + + 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) { + if (!next_origin(msg, query)) { + printmessage(query, msg, ISC_TRUE); + received(b->used, &sevent->address, query); + } + } else if (!l->trace && !l->ns_search_only) { + 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 + printmessage(query, msg, ISC_TRUE); + } + } + + 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) + 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) + { + dns_message_destroy(&msg); + cancel_lookup(l); + } + clear_query(query); + check_next_lookup(l); + } + if (msg != NULL) + dns_message_destroy(&msg); + isc_event_free(&event); + UNLOCK_LOOKUP; +} + +/* + * 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. + */ +void +get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) { + struct in_addr in4; + struct in6_addr in6; +#ifdef USE_GETADDRINFO + struct addrinfo *res = NULL, hints; + int result; +#else + struct hostent *he; +#endif + + debug("get_address()"); + + if (inet_pton(AF_INET6, host, &in6) == 1) { + if (!have_ipv6) + fatal("Protocol family INET6 not supported '%s'", host); + isc_sockaddr_fromin6(sockaddr, &in6, port); + } else if (inet_pton(AF_INET, host, &in4) == 1) { + if (have_ipv4) + isc_sockaddr_fromin(sockaddr, &in4, port); + else + isc_sockaddr_v6fromin(sockaddr, &in4, port); + } else { +#ifdef USE_GETADDRINFO + memset(&hints, 0, sizeof(hints)); + if (specified_source) + hints.ai_family = isc_sockaddr_pf(&bind_address); + else if (!have_ipv6) + hints.ai_family = PF_INET; + else if (!have_ipv4) + hints.ai_family = PF_INET6; + else { + hints.ai_family = PF_UNSPEC; +#ifdef AI_ADDRCONFIG + hints.ai_flags = AI_ADDRCONFIG; +#endif + } + debug ("before getaddrinfo()"); + isc_app_block(); +#ifdef AI_ADDRCONFIG + again: +#endif + result = getaddrinfo(host, NULL, &hints, &res); +#ifdef AI_ADDRCONFIG + if (result == EAI_BADFLAGS && + (hints.ai_flags & AI_ADDRCONFIG) != 0) { + hints.ai_flags &= ~AI_ADDRCONFIG; + goto again; + } +#endif + isc_app_unblock(); + if (result != 0) { + fatal("Couldn't find server '%s': %s", + host, gai_strerror(result)); + } + memcpy(&sockaddr->type.sa, res->ai_addr, res->ai_addrlen); + sockaddr->length = res->ai_addrlen; + isc_sockaddr_setport(sockaddr, port); + freeaddrinfo(res); +#else + debug ("before gethostbyname()"); + isc_app_block(); + he = gethostbyname(host); + isc_app_unblock(); + if (he == NULL) + fatal("Couldn't find server '%s' (h_errno=%d)", + host, h_errno); + INSIST(he->h_addrtype == AF_INET); + isc_sockaddr_fromin(sockaddr, + (struct in_addr *)(he->h_addr_list[0]), + port); +#endif + } +} + +/* + * 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("cancelling 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) { + void *ptr; + dig_server_t *s; + + 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; + + s = ISC_LIST_HEAD(server_list); + while (s != NULL) { + debug("freeing global server %p", s); + ptr = s; + s = ISC_LIST_NEXT(s, link); + isc_mem_free(mctx, ptr); + } + clear_searchlist(); + 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); + if (memdebugging != 0) + isc_mem_stats(mctx, stderr); + if (mctx != NULL) + isc_mem_destroy(&mctx); +} diff --git a/contrib/bind-9.2.4rc7/bin/dig/host.1 b/contrib/bind-9.2.4rc7/bin/dig/host.1 new file mode 100644 index 0000000000..7201e9d0a4 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dig/host.1 @@ -0,0 +1,130 @@ +.\" Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2000-2003 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: host.1,v 1.11.2.2 2004/03/15 04:44:38 marka Exp $ +.\" +.TH "HOST" "1" "Jun 30, 2000" "BIND9" "" +.SH NAME +host \- DNS lookup utility +.SH SYNOPSIS +.sp +\fBhost\fR [ \fB-aCdlnrTwv\fR ] [ \fB-c \fIclass\fB\fR ] [ \fB-N \fIndots\fB\fR ] [ \fB-R \fInumber\fB\fR ] [ \fB-t \fItype\fB\fR ] [ \fB-W \fIwait\fB\fR ] \fBname\fR [ \fBserver\fR ] +.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. The argument is provided for +compatibility with older implementations. This option is equivalent +to making a query of type AXFR. +.PP +The \fB-n\fR +option specifies that reverse lookups of IPv6 addresses should +use the IP6.INT domain and "nibble" labels as defined in RFC1886. +The default is to use IP6.ARPA and binary labels as defined in RFC2874. +.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 behaviour 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-t\fR option is used to select the query type. +\fItype\fR can be any recognised 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 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. +.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. +.SH "FILES" +.PP +\fI/etc/resolv.conf\fR +.SH "SEE ALSO" +.PP +\fBdig\fR(1), +\fBnamed\fR(8). diff --git a/contrib/bind-9.2.4rc7/bin/dig/host.c b/contrib/bind-9.2.4rc7/bin/dig/host.c new file mode 100644 index 0000000000..403481d2df --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dig/host.c @@ -0,0 +1,728 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2003 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: host.c,v 1.76.2.6 2004/03/09 06:09:13 marka Exp $ */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +extern ISC_LIST(dig_lookup_t) lookup_list; +extern ISC_LIST(dig_server_t) server_list; +extern ISC_LIST(dig_searchlist_t) search_list; + +extern isc_boolean_t usesearch; +extern isc_boolean_t debugging; +extern unsigned int timeout; +extern isc_mem_t *mctx; +extern int ndots; +extern int tries; +extern char *progname; +extern isc_task_t *global_task; +extern int fatalexit; + +static isc_boolean_t short_form = ISC_TRUE, listed_server = ISC_FALSE; +static isc_boolean_t list_addresses = ISC_TRUE; +static dns_rdatatype_t list_type = dns_rdatatype_a; + +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" +}; + +static const char *rtypetext[] = { + "zero", /* 0 */ + "has address", /* 1 */ + "name server", /* 2 */ + "MD", /* 3 */ + "MF", /* 4 */ + "is an alias for", /* 5 */ + "SOA", /* 6 */ + "MB", /* 7 */ + "MG", /* 8 */ + "MR", /* 9 */ + "NULL", /* 10 */ + "has well known services", /* 11 */ + "domain name pointer", /* 12 */ + "host information", /* 13 */ + "MINFO", /* 14 */ + "mail is handled by", /* 15 */ + "text", /* 16 */ + "RP", /* 17 */ + "AFSDB", /* 18 */ + "x25 address", /* 19 */ + "isdn address", /* 20 */ + "RT", /* 21 */ + "NSAP", /* 22 */ + "NSAP_PTR", /* 23 */ + "has signature", /* 24 */ + "has key", /* 25 */ + "PX", /* 26 */ + "GPOS", /* 27 */ + "has AAAA address", /* 28 */ + "LOC", /* 29 */ + "has next record", /* 30 */ + "EID", /* 31 */ + "NIMLOC", /* 32 */ + "SRV", /* 33 */ + "ATMA", /* 34 */ + "NAPTR", /* 35 */ + "KX", /* 36 */ + "CERT", /* 37 */ + "has v6 address", /* 38 */ + "DNAME", /* 39 */ + "has optional information", /* 41 */ + "has 42 record", /* 42 */ + "has 43 record", /* 43 */ + "has 44 record", /* 44 */ + "has 45 record", /* 45 */ + "has 46 record", /* 46 */ + "has 47 record", /* 47 */ + "has 48 record", /* 48 */ + "has 49 record", /* 49 */ + "has 50 record", /* 50 */ + "has 51 record", /* 51 */ + "has 52 record", /* 52 */ + "has 53 record", /* 53 */ + "has 54 record", /* 54 */ + "has 55 record", /* 55 */ + "has 56 record", /* 56 */ + "has 57 record", /* 57 */ + "has 58 record", /* 58 */ + "has 59 record", /* 59 */ + "has 60 record", /* 60 */ + "has 61 record", /* 61 */ + "has 62 record", /* 62 */ + "has 63 record", /* 63 */ + "has 64 record", /* 64 */ + "has 65 record", /* 65 */ + "has 66 record", /* 66 */ + "has 67 record", /* 67 */ + "has 68 record", /* 68 */ + "has 69 record", /* 69 */ + "has 70 record", /* 70 */ + "has 71 record", /* 71 */ + "has 72 record", /* 72 */ + "has 73 record", /* 73 */ + "has 74 record", /* 74 */ + "has 75 record", /* 75 */ + "has 76 record", /* 76 */ + "has 77 record", /* 77 */ + "has 78 record", /* 78 */ + "has 79 record", /* 79 */ + "has 80 record", /* 80 */ + "has 81 record", /* 81 */ + "has 82 record", /* 82 */ + "has 83 record", /* 83 */ + "has 84 record", /* 84 */ + "has 85 record", /* 85 */ + "has 86 record", /* 86 */ + "has 87 record", /* 87 */ + "has 88 record", /* 88 */ + "has 89 record", /* 89 */ + "has 90 record", /* 90 */ + "has 91 record", /* 91 */ + "has 92 record", /* 92 */ + "has 93 record", /* 93 */ + "has 94 record", /* 94 */ + "has 95 record", /* 95 */ + "has 96 record", /* 96 */ + "has 97 record", /* 97 */ + "has 98 record", /* 98 */ + "has 99 record", /* 99 */ + "UINFO", /* 100 */ + "UID", /* 101 */ + "GID", /* 102 */ + "UNSPEC"}; /* 103 */ + + +static void +show_usage(void) { + fputs( +"Usage: host [-aCdlrTwv] [-c class] [-n] [-N ndots] [-t type] [-W time]\n" +" [-R number] hostname [server]\n" +" -a is equivalent to -v -t *\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 Use the old IN6.INT form of IPv6 reverse lookup\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" +" -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", 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; + isc_result_t result; + int diff; + + if (!short_form) { + char fromtext[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_format(from, fromtext, sizeof(fromtext)); + result = isc_time_now(&now); + check_result(result, "isc_time_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); +} + + +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; + const char *rtt; + + 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) { + dns_rdataset_current(rdataset, &rdata); + if (rdata.type <= 103) + rtt = rtypetext[rdata.type]; + else if (rdata.type == 249) + rtt = "key"; + else if (rdata.type == 250) + rtt = "signature"; + else + rtt = "unknown"; + 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); +} + +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; + + UNUSED(headers); + + if (listed_server) { + char sockstr[ISC_SOCKADDR_FORMATSIZE]; + + printf("Using domain server:\n"); + printf("Name: %s\n", query->servname); + isc_sockaddr_format(&query->sockaddr, sockstr, + sizeof(sockstr)); + printf("Address: %s\n", sockstr); + printf("Aliases: \n\n"); + } + + 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", namestr, + msg->rcode, rcodetext[msg->rcode]); + return (ISC_R_SUCCESS); + } + if (!short_form) { + printf(";; ->>HEADER<<- opcode: %s, status: %s, id: %u\n", + opcodetext[msg->opcode], rcodetext[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"); + + return (result); +} + +static void +parse_args(isc_boolean_t is_batchfile, int argc, char **argv) { + char hostname[MXNAME]; + dig_server_t *srv; + 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; + + UNUSED(is_batchfile); + + lookup = make_empty_lookup(); + + while ((c = isc_commandline_parse(argc, argv, "ilvwrdt:c:aTCN:R:W:Dn")) + != EOF) { + 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': + 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; + if (rdtype == dns_rdatatype_axfr) { + /* -l -t any -v */ + list_type = dns_rdatatype_any; + short_form = ISC_FALSE; + lookup->tcp_mode = ISC_TRUE; + } else + list_type = rdtype; + list_addresses = 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; + } + 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; + break; + case 'i': + lookup->ip6_int = ISC_TRUE; + break; + case 'n': + 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); + if (tries < 1) + tries = 1; + 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; + break; + case 'N': + debug("setting NDOTS to %s", + isc_commandline_argument); + ndots = atoi(isc_commandline_argument); + break; + case 'D': + debugging = ISC_TRUE; + break; + } + } + 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) { + srv = make_server(argv[isc_commandline_index+1]); + debug("server is %s", srv->servername); + ISC_LIST_APPEND(server_list, srv, link); + listed_server = ISC_TRUE; + } + + lookup->pending = ISC_FALSE; + if (get_reverse(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; + } else { + strncpy(lookup->textname, hostname, sizeof(lookup->textname)); + lookup->textname[sizeof(lookup->textname)-1]=0; + } + lookup->new_search = ISC_TRUE; + ISC_LIST_APPEND(lookup_list, lookup, link); + + usesearch = ISC_TRUE; +} + +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); + + fatalexit = 1; + + debug("main()"); + progname = argv[0]; + 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 (0); +} + diff --git a/contrib/bind-9.2.4rc7/bin/dig/host.html b/contrib/bind-9.2.4rc7/bin/dig/host.html new file mode 100644 index 0000000000..c912fb3cb4 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dig/host.html @@ -0,0 +1,443 @@ + + + + +host

host

Name

host -- DNS lookup utility

Synopsis

host [-aCdlnrTwv] [-c class] [-N ndots] [-R number] [-t type] [-W wait] {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. The argument is provided for +compatibility with older implementations. This option is equivalent +to making a query of type AXFR.

The -n +option specifies that reverse lookups of IPv6 addresses should +use the IP6.INT domain and "nibble" labels as defined in RFC1886. +The default is to use IP6.ARPA and binary labels as defined in RFC2874.

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 behaviour 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 -t option is used to select the query type. +type can be any recognised 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 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.

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.

FILES

/etc/resolv.conf

SEE ALSO

dig(1), +named(8).

diff --git a/contrib/bind-9.2.4rc7/bin/dig/include/dig/dig.h b/contrib/bind-9.2.4rc7/bin/dig/include/dig/dig.h new file mode 100644 index 0000000000..3b2d9e6a47 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dig/include/dig/dig.h @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001, 2003 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: dig.h,v 1.71.2.7 2004/03/09 06:09:14 marka Exp $ */ + +#ifndef DIG_H +#define DIG_H + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MXSERV 6 +#define MXNAME (DNS_NAME_MAXTEXT+1) +#define MXRD 32 +#define BUFSIZE 512 +#define COMMSIZE 0xffff +#ifndef RESOLV_CONF +#define RESOLV_CONF "/etc/resolv.conf" +#endif +#define OUTPUTBUF 32767 +#define MAXRRLIMIT 0xffffffff +#define MAXTIMEOUT 0xffff +#define MAXTRIES 0xffffffff +#define MAXNDOTS 0xffff +#define MAXPORT 0xffff +#define MAXSERIAL 0xffffffff + +/* + * Default timeout values + */ +#define TCP_TIMEOUT 10 +#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. + */ + +#define ROOTNS 1 +/* + * Set the number of root servers to ask for information when running in + * trace mode. + * XXXMWS -- trace mode is currently semi-broken, and this number *MUST* + * be 1. + */ + +ISC_LANG_BEGINDECLS + +typedef struct dig_lookup dig_lookup_t; +typedef struct dig_query dig_query_t; +typedef struct dig_server dig_server_t; +typedef ISC_LIST(dig_server_t) dig_serverlist_t; +typedef struct dig_searchlist dig_searchlist_t; + +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, + besteffort, + dnssec; + char textname[MXNAME]; /* Name we're going to be looking up */ + char cmdline[MXNAME]; + dns_rdatatype_t rdtype; + dns_rdatatype_t qrdtype; + 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 sendbuf; + 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_uint32_t ixfr_serial; + isc_buffer_t rdatabuf; + char rdatastore[MXNAME]; + dst_context_t *tsigctx; + isc_buffer_t *querysig; + isc_uint32_t msgcounter; +}; + +struct dig_query { + dig_lookup_t *lookup; + isc_boolean_t waiting_connect, + 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 rr_count; + char *servname; + 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; +}; + +struct dig_server { + char servername[MXNAME]; + ISC_LINK(dig_server_t) link; +}; + +struct dig_searchlist { + char origin[MXNAME]; + ISC_LINK(dig_searchlist_t) link; +}; + +/* + * Routines in dighost.c. + */ +void +get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr); + +isc_result_t +get_reverse(char *reverse, char *value, isc_boolean_t ip6int, + 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 +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); + +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); + +/* + * Routines to be defined in dig.c, host.c, and nslookup.c. + */ + +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); + +ISC_LANG_ENDDECLS + +#endif diff --git a/contrib/bind-9.2.4rc7/bin/dig/nslookup.c b/contrib/bind-9.2.4rc7/bin/dig/nslookup.c new file mode 100644 index 0000000000..28244b685e --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dig/nslookup.c @@ -0,0 +1,882 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2003 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: nslookup.c,v 1.90.2.7 2004/06/07 03:59:08 marka Exp $ */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +extern ISC_LIST(dig_lookup_t) lookup_list; +extern ISC_LIST(dig_server_t) server_list; +extern ISC_LIST(dig_searchlist_t) search_list; + +extern isc_boolean_t have_ipv6, usesearch, qr, debugging; +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 tries; +extern int lookup_counter; +extern int exitcode; +extern isc_taskmgr_t *taskmgr; +extern isc_task_t *global_task; +extern char *progname; + +static isc_boolean_t short_form = ISC_TRUE, + tcpmode = ISC_FALSE, deprecation_msg = ISC_TRUE, + 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; +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); + +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)); +} + +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->servname); + 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", nametext, + rcodetext[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; + + srv = ISC_LIST_HEAD(server_list); + + while (srv != NULL) { + char sockstr[ISC_SOCKADDR_FORMATSIZE]; + + get_address(srv->servername, port, &sockaddr); + isc_sockaddr_format(&sockaddr, sockstr, sizeof(sockstr)); + printf("Default server: %s\nAddress: %s\n", + srv->servername, 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 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) { + port = atoi(&opt[5]); + } else if (strncasecmp(opt, "po=", 3) == 0) { + port = atoi(&opt[3]); + } else if (strncasecmp(opt, "timeout=", 8) == 0) { + timeout = atoi(&opt[8]); + } else if (strncasecmp(opt, "t=", 2) == 0) { + timeout = atoi(&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) { + tries = atoi(&opt[6]); + } else if (strncasecmp(opt, "ret=", 4) == 0) { + tries = atoi(&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; + } else if (strncasecmp(opt, "nodeb", 5) == 0) { + short_form = ISC_TRUE; + } 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 { + 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, 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; + 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 +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); + } +} + +/* + * This works on the global server list, instead of on a per-lookup + * server list, since the change is persistent. + */ +static void +setsrv(char *opt) { + dig_server_t *srv; + + if (opt == NULL) + return; + + flush_server_list(); + srv = isc_mem_allocate(mctx, sizeof(struct dig_server)); + if (srv == NULL) + fatal("memory allocation failure"); + safecpy(srv->servername, opt, sizeof(srv->servername)); + ISC_LIST_INITANDAPPEND(server_list, srv, link); +} + +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); + 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)) { + setsrv(arg); + 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 + setsrv(argv[0]); + } + } +} + +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); + + result = isc_app_start(); + check_result(result, "isc_app_start"); + + setup_libs(); + progname = argv[0]; + + parse_args(argc, argv); + + if (deprecation_msg) { + fputs( +"Note: nslookup is deprecated and may be removed from future releases.\n" +"Consider using the `dig' or `host' programs instead. Run nslookup with\n" +"the `-sil[ent]' option to prevent this message from appearing.\n", stderr); + } + 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.2.4rc7/bin/dnssec/dnssec-keygen.8 b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-keygen.8 new file mode 100644 index 0000000000..297c872d92 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-keygen.8 @@ -0,0 +1,168 @@ +.\" Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2000, 2001 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: dnssec-keygen.8,v 1.19.2.2 2004/06/03 05:21:09 marka Exp $ +.\" +.TH "DNSSEC-KEYGEN" "8" "June 30, 2000" "BIND9" "" +.SH NAME +dnssec-keygen \- DNSSEC key generation tool +.SH SYNOPSIS +.sp +\fBdnssec-keygen\fR \fB-a \fIalgorithm\fB\fR \fB-b \fIkeysize\fB\fR \fB-n \fInametype\fB\fR [ \fB-c \fIclass\fB\fR ] [ \fB-e\fR ] [ \fB-g \fIgenerator\fB\fR ] [ \fB-h\fR ] [ \fB-p \fIprotocol\fB\fR ] [ \fB-r \fIrandomdev\fB\fR ] [ \fB-s \fIstrength\fB\fR ] [ \fB-t \fItype\fB\fR ] [ \fB-v \fIlevel\fB\fR ] \fBname\fR +.SH "DESCRIPTION" +.PP +\fBdnssec-keygen\fR generates keys for DNSSEC +(Secure DNS), as defined in RFC 2535. It can also generate +keys for use with TSIG (Transaction Signatures), as +defined in RFC 2845. +.SH "OPTIONS" +.TP +\fB-a \fIalgorithm\fB\fR +Selects the cryptographic algorithm. The value of +\fBalgorithm\fR must be one of RSAMD5 or RSA, +DSA, DH (Diffie Hellman), or HMAC-MD5. These values +are case insensitive. + +Note that for DNSSEC, DSA is a mandatory to implement algorithm, +and RSA is recommended. For TSIG, HMAC-MD5 is mandatory. +.TP +\fB-b \fIkeysize\fB\fR +Specifies the number of bits in the key. The choice of key +size depends on the algorithm used. RSA 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. +.TP +\fB-n \fInametype\fB\fR +Specifies the owner type of the key. The value of +\fBnametype\fR must either be ZONE (for a DNSSEC +zone key), HOST or ENTITY (for a key associated with a host), +or USER (for a key associated with a user). These values are +case insensitive. +.TP +\fB-c \fIclass\fB\fR +Indicates that the DNS record containing the key should have +the specified class. If not specified, class IN is used. +.TP +\fB-e\fR +If generating an RSA key, use a large exponent. +.TP +\fB-g \fIgenerator\fB\fR +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. +.TP +\fB-h\fR +Prints a short summary of the options and arguments to +\fBdnssec-keygen\fR. +.TP +\fB-p \fIprotocol\fB\fR +Sets the protocol value for the generated key. The protocol +is a number between 0 and 255. The default is 2 (email) for +keys of type USER and 3 (DNSSEC) for all other key types. +Other possible values for this argument are listed in +RFC 2535 and its successors. +.TP +\fB-r \fIrandomdev\fB\fR +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. +.TP +\fB-s \fIstrength\fB\fR +Specifies the strength value of the key. The strength is +a number between 0 and 15, and currently has no defined +purpose in DNSSEC. +.TP +\fB-t \fItype\fB\fR +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. +.TP +\fB-v \fIlevel\fB\fR +Sets the debugging level. +.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. These strings can be used as arguments +to \fBdnssec-makekeyset\fR. +.TP 0.2i +\(bu +\fInnnn\fR is the key name. +.TP 0.2i +\(bu +\fIaaa\fR is the numeric representation of the +algorithm. +.TP 0.2i +\(bu +\fIiiiii\fR is the key identifier (or footprint). +.PP +\fBdnssec-keygen\fR creates two file, 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 +.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 +.PP +The \fI.private\fR file contains algorithm specific +fields. For obvious security reasons, this file does not have +general read permission. +.PP +.PP +Both \fI.key\fR and \fI.private\fR +files are generated for symmetric encryption algorithm such as +HMAC-MD5, even though the public and private key are equivalent. +.PP +.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-makekeyset\fR(8), +\fBdnssec-signkey\fR(8), +\fBdnssec-signzone\fR(8), +\fIBIND 9 Administrator Reference Manual\fR, +\fIRFC 2535\fR, +\fIRFC 2845\fR, +\fIRFC 2539\fR. +.SH "AUTHOR" +.PP +Internet Systems Consortium diff --git a/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-keygen.c b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-keygen.c new file mode 100644 index 0000000000..103cc124cc --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-keygen.c @@ -0,0 +1,402 @@ +/* + * Portions Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2000, 2001 Internet Software Consortium. + * Portions Copyright (C) 1995-2000 by Network Associates, 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 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.48.2.2 2004/03/09 06:09:14 marka Exp $ */ + +#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 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, "Required options:\n"); + fprintf(stderr, " -a algorithm: RSA | RSAMD5 | DH | DSA | HMAC-MD5" + "\n"); + fprintf(stderr, " -b key size, in bits:\n"); + fprintf(stderr, " RSA:\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, " -n nametype: ZONE | HOST | ENTITY | USER\n"); + fprintf(stderr, " name: owner of the key\n"); + fprintf(stderr, "Other options:\n"); + fprintf(stderr, " -c class (default: IN)\n"); + fprintf(stderr, " -e use large exponent (RSA only)\n"); + fprintf(stderr, " -g use specified generator (DH only)\n"); + fprintf(stderr, " -t type: AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF " + "(default: AUTHCONF)\n"); + fprintf(stderr, " -p protocol value " + "(default: 2 [email] for USER, 3 [dnssec] otherwise)\n"); + fprintf(stderr, " -s strength value this key signs DNS records " + "with (default: 0)\n"); + fprintf(stderr, " -r randomdev (a file containing random data)\n"); + fprintf(stderr, " -v verbose level\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 *randomfile = NULL; + char *prog, *endp; + dst_key_t *key = NULL, *oldkey; + dns_fixedname_t fname; + dns_name_t *name; + isc_uint16_t flags = 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; + + RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS); + + if ((prog = strrchr(argv[0],'/')) == NULL) + prog = isc_mem_strdup(mctx, argv[0]); + else + prog = isc_mem_strdup(mctx, ++prog); + if (prog == NULL) + fatal("out of memory"); + + if (argc == 1) + usage(); + + dns_result_register(); + + while ((ch = isc_commandline_parse(argc, argv, + "a:b:c:eg:n:t:p:s:hr:v:")) != -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 'e': + rsa_exp = 1; + break; + case 'g': + generator = strtol(isc_commandline_argument, + &endp, 10); + if (*endp != '\0' || generator <= 0) + fatal("-g requires a positive number"); + break; + case 'n': + nametype = isc_commandline_argument; + if (nametype == NULL) + fatal("out of memory"); + break; + case 't': + type = isc_commandline_argument; + if (type == NULL) + fatal("out of memory"); + 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': + randomfile = isc_commandline_argument; + 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 'h': + usage(); + default: + fprintf(stderr, "%s: invalid argument -%c\n", + program, ch); + usage(); + } + } + + setup_entropy(mctx, randomfile, &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) + alg = DNS_KEYALG_RSA; + else if (strcasecmp(algname, "HMAC-MD5") == 0) + alg = DST_ALG_HMACMD5; + 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 (type != NULL) { + 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_RSA: + 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); + break; + } + + if (alg != DNS_KEYALG_RSA && rsa_exp != 0) + fatal("specified RSA exponent without RSA"); + + if (alg != DNS_KEYALG_DH && generator != 0) + fatal("specified DH generator without DH"); + + if (nametype == NULL) + fatal("no nametype specified"); + if (strcasecmp(nametype, "zone") == 0) + flags |= DNS_KEYOWNER_ZONE; + else 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 nametype %s", nametype); + + if (classname != NULL) { + r.base = classname; + r.length = strlen(classname); + ret = dns_rdataclass_fromtext(&rdclass, &r); + if (ret != ISC_R_SUCCESS) + fatal("unknown class %s",classname); + } else + rdclass = dns_rdataclass_in; + + flags |= signatory; + + if (protocol == -1) { + if ((flags & DNS_KEYFLAG_OWNERMASK) == DNS_KEYOWNER_USER) + protocol = DNS_KEYPROTO_EMAIL; + else + protocol = DNS_KEYPROTO_DNSSEC; + } + + 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"); + } + + 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_RSA: + param = rsa_exp; + break; + case DNS_KEYALG_DH: + param = generator; + break; + case DNS_KEYALG_DSA: + case DST_ALG_HMACMD5: + 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); + } + + /* + * 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, DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, 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); + isc_mem_free(mctx, prog); + dst_key_free(&key); + + cleanup_logging(&log); + cleanup_entropy(&ectx); + dst_lib_destroy(); + if (verbose > 10) + isc_mem_stats(mctx, stdout); + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-keygen.html b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-keygen.html new file mode 100644 index 0000000000..18d8cdfd8f --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-keygen.html @@ -0,0 +1,575 @@ + + + + +dnssec-keygen

dnssec-keygen

Name

dnssec-keygen -- DNSSEC key generation tool

Synopsis

dnssec-keygen {-a algorithm} {-b keysize} {-n nametype} [-c class] [-e] [-g generator] [-h] [-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. 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 or RSA, + DSA, DH (Diffie Hellman), or HMAC-MD5. These values + are case insensitive. +

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

-b keysize

Specifies the number of bits in the key. The choice of key + size depends on the algorithm used. RSA 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), HOST or ENTITY (for a key associated with a host), + or USER (for a key associated with a user). These values are + case insensitive. +

-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 RSA key, use a large exponent. +

-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. +

-p protocol

Sets the protocol value for the generated key. The protocol + is a number between 0 and 255. The default is 2 (email) for + keys of type USER and 3 (DNSSEC) for all other key types. + 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. These strings can be used as arguments + to dnssec-makekeyset. +

  • nnnn is the key name. +

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

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

dnssec-keygen creates two file, 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 algorithm 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-makekeyset(8), + dnssec-signkey(8), + dnssec-signzone(8), + BIND 9 Administrator Reference Manual, + RFC 2535, + RFC 2845, + RFC 2539. +

AUTHOR

Internet Systems Consortium +

diff --git a/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-makekeyset.8 b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-makekeyset.8 new file mode 100644 index 0000000000..63526add32 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-makekeyset.8 @@ -0,0 +1,113 @@ +.\" Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2000, 2001, 2003 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: dnssec-makekeyset.8,v 1.16.2.4 2004/06/03 05:21:10 marka Exp $ +.\" +.TH "DNSSEC-MAKEKEYSET" "8" "June 30, 2000" "BIND9" "" +.SH NAME +dnssec-makekeyset \- DNSSEC zone signing tool +.SH SYNOPSIS +.sp +\fBdnssec-makekeyset\fR [ \fB-a\fR ] [ \fB-s \fIstart-time\fB\fR ] [ \fB-e \fIend-time\fB\fR ] [ \fB-h\fR ] [ \fB-p\fR ] [ \fB-r \fIrandomdev\fB\fR ] [ \fB-t\fIttl\fB\fR ] [ \fB-v \fIlevel\fB\fR ] \fBkey\fR\fI...\fR +.SH "DESCRIPTION" +.PP +\fBdnssec-makekeyset\fR generates a key set from one +or more keys created by \fBdnssec-keygen\fR. It creates +a file containing a KEY record for each key, and self-signs the key +set with each zone key. The output file is of the form +\fIkeyset-nnnn.\fR, where \fInnnn\fR +is the zone name. +.SH "OPTIONS" +.TP +\fB-a\fR +Verify all generated signatures. +.TP +\fB-s \fIstart-time\fB\fR +Specify the date and time when the generated SIG 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 is used. +.TP +\fB-e \fIend-time\fB\fR +Specify the date and time when the generated SIG 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. +.TP +\fB-h\fR +Prints a short summary of the options and arguments to +\fBdnssec-makekeyset\fR. +.TP +\fB-p\fR +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. +.TP +\fB-r \fIrandomdev\fB\fR +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. +.TP +\fB-t \fIttl\fB\fR +Specify the TTL (time to live) of the KEY and SIG records. +The default is 3600 seconds. +.TP +\fB-v \fIlevel\fB\fR +Sets the debugging level. +.TP +\fBkey\fR +The list of keys to be included in the keyset file. These keys +are expressed in the form \fIKnnnn.+aaa+iiiii\fR +as generated by \fBdnssec-keygen\fR. +.SH "EXAMPLE" +.PP +The following command generates a keyset containing the DSA key for +\fBexample.com\fR generated in the +\fBdnssec-keygen\fR man page. +.PP +\fBdnssec-makekeyset -t 86400 -s 20000701120000 -e +2592000 Kexample.com.+003+26160\fR +.PP +In this example, \fBdnssec-makekeyset\fR creates +the file \fIkeyset-example.com.\fR. This file +contains the specified key and a self-generated signature. +.PP +The DNS administrator for \fBexample.com\fR could +send \fIkeyset-example.com.\fR to the DNS +administrator for \fB.com\fR for signing, if the +\&.com zone is DNSSEC-aware and the administrators of the two zones +have some mechanism for authenticating each other and exchanging +the keys and signatures securely. +.SH "SEE ALSO" +.PP +\fBdnssec-keygen\fR(8), +\fBdnssec-signkey\fR(8), +\fIBIND 9 Administrator Reference Manual\fR, +\fIRFC 2535\fR. +.SH "AUTHOR" +.PP +Internet Systems Consortium diff --git a/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-makekeyset.c b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-makekeyset.c new file mode 100644 index 0000000000..ab7932d150 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-makekeyset.c @@ -0,0 +1,466 @@ +/* + * Portions Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2000, 2001 Internet Software Consortium. + * Portions Copyright (C) 1995-2000 by Network Associates, 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 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-makekeyset.c,v 1.52.2.2 2004/03/09 06:09:15 marka Exp $ */ + +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "dnssectool.h" + +#define BUFSIZE 2048 + +const char *program = "dnssec-makekeyset"; +int verbose; + +typedef struct keynode keynode_t; +struct keynode { + dst_key_t *key; + ISC_LINK(keynode_t) link; +}; +typedef ISC_LIST(keynode_t) keylist_t; + +static isc_stdtime_t starttime = 0, endtime = 0, now; +static int ttl = -1; + +static isc_mem_t *mctx = NULL; +static isc_entropy_t *ectx = NULL; + +static keylist_t keylist; + +static void +usage(void) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\t%s [options] keys\n", program); + + fprintf(stderr, "\n"); + + fprintf(stderr, "Options: (default value in parenthesis) \n"); + fprintf(stderr, "\t-a\n"); + fprintf(stderr, "\t\tverify generated signatures\n"); + fprintf(stderr, "\t-s YYYYMMDDHHMMSS|+offset:\n"); + fprintf(stderr, "\t\tSIG start time - absolute|offset (now)\n"); + fprintf(stderr, "\t-e YYYYMMDDHHMMSS|+offset|\"now\"+offset]:\n"); + fprintf(stderr, "\t\tSIG end time - " + "absolute|from start|from now (now + 30 days)\n"); + fprintf(stderr, "\t-t ttl\n"); + fprintf(stderr, "\t-p\n"); + fprintf(stderr, "\t\tuse pseudorandom data (faster but less secure)\n"); + fprintf(stderr, "\t-r randomdev:\n"); + fprintf(stderr, "\t\ta file containing random data\n"); + fprintf(stderr, "\t-v level:\n"); + fprintf(stderr, "\t\tverbose level (0)\n"); + + fprintf(stderr, "\n"); + + fprintf(stderr, "keys:\n"); + fprintf(stderr, "\tkeyfile (Kname+alg+tag)\n"); + + fprintf(stderr, "\n"); + + fprintf(stderr, "Output:\n"); + fprintf(stderr, "\tkeyset (keyset-)\n"); + exit(0); +} + +static isc_boolean_t +zonekey_on_list(dst_key_t *key) { + keynode_t *keynode; + for (keynode = ISC_LIST_HEAD(keylist); + keynode != NULL; + keynode = ISC_LIST_NEXT(keynode, link)) + { + if (dst_key_compare(keynode->key, key)) + return (ISC_TRUE); + } + return (ISC_FALSE); +} + +static isc_boolean_t +rdata_on_list(dns_rdata_t *rdata, dns_rdatalist_t *list) { + dns_rdata_t *trdata; + for (trdata = ISC_LIST_HEAD(list->rdata); + trdata != NULL; + trdata = ISC_LIST_NEXT(trdata, link)) + { + if (dns_rdata_compare(trdata, rdata) == 0) + return (ISC_TRUE); + } + return (ISC_FALSE); +} + +int +main(int argc, char *argv[]) { + int i, ch; + char *startstr = NULL, *endstr = NULL; + char *randomfile = NULL; + dns_fixedname_t fdomain; + dns_name_t *domain = NULL; + char *output = NULL; + char *endp; + unsigned char *data; + dns_db_t *db; + dns_dbnode_t *node; + dns_dbversion_t *version; + dst_key_t *key = NULL; + dns_rdata_t *rdata; + dns_rdatalist_t rdatalist, sigrdatalist; + dns_rdataset_t rdataset, sigrdataset; + isc_result_t result; + isc_buffer_t b; + isc_region_t r; + isc_log_t *log = NULL; + keynode_t *keynode; + dns_name_t *savedname = NULL; + unsigned int eflags; + isc_boolean_t pseudorandom = ISC_FALSE; + isc_boolean_t tryverify = ISC_FALSE; + + result = isc_mem_create(0, 0, &mctx); + if (result != ISC_R_SUCCESS) + fatal("failed to create memory context: %s", + isc_result_totext(result)); + + dns_result_register(); + + while ((ch = isc_commandline_parse(argc, argv, "as:e:t:r:v:ph")) != -1) + { + switch (ch) { + case 'a': + tryverify = ISC_TRUE; + break; + case 's': + startstr = isc_commandline_argument; + break; + + case 'e': + endstr = isc_commandline_argument; + break; + + case 't': + endp = NULL; + ttl = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') + fatal("TTL must be numeric"); + break; + + case 'r': + randomfile = isc_commandline_argument; + break; + + case 'v': + endp = NULL; + verbose = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') + fatal("verbose level must be numeric"); + break; + + case 'p': + pseudorandom = ISC_TRUE; + break; + + case 'h': + default: + usage(); + + } + } + + argc -= isc_commandline_index; + argv += isc_commandline_index; + + if (argc < 1) + usage(); + + setup_entropy(mctx, randomfile, &ectx); + eflags = ISC_ENTROPY_BLOCKING; + if (!pseudorandom) + eflags |= ISC_ENTROPY_GOODONLY; + result = dst_lib_init(mctx, ectx, eflags); + if (result != ISC_R_SUCCESS) + fatal("could not initialize dst: %s", + isc_result_totext(result)); + + isc_stdtime_get(&now); + + if (startstr != NULL) + starttime = strtotime(startstr, now, now); + else + starttime = now; + + if (endstr != NULL) + endtime = strtotime(endstr, now, starttime); + else + endtime = starttime + (30 * 24 * 60 * 60); + + if (ttl == -1) { + ttl = 3600; + fprintf(stderr, "%s: TTL not specified, assuming 3600\n", + program); + } + + setup_logging(verbose, mctx, &log); + + dns_rdatalist_init(&rdatalist); + rdatalist.rdclass = 0; + rdatalist.type = dns_rdatatype_key; + rdatalist.covers = 0; + rdatalist.ttl = ttl; + + ISC_LIST_INIT(keylist); + + for (i = 0; i < argc; i++) { + char namestr[DNS_NAME_FORMATSIZE]; + isc_buffer_t namebuf; + + key = NULL; + result = dst_key_fromnamedfile(argv[i], DST_TYPE_PUBLIC, + mctx, &key); + if (result != ISC_R_SUCCESS) + fatal("error loading key from %s: %s", argv[i], + isc_result_totext(result)); + if (rdatalist.rdclass == 0) + rdatalist.rdclass = dst_key_class(key); + + isc_buffer_init(&namebuf, namestr, sizeof namestr); + result = dns_name_tofilenametext(dst_key_name(key), + ISC_FALSE, + &namebuf); + check_result(result, "dns_name_tofilenametext"); + isc_buffer_putuint8(&namebuf, 0); + + if (savedname == NULL) { + savedname = isc_mem_get(mctx, sizeof(dns_name_t)); + if (savedname == NULL) + fatal("out of memory"); + dns_name_init(savedname, NULL); + result = dns_name_dup(dst_key_name(key), mctx, + savedname); + if (result != ISC_R_SUCCESS) + fatal("out of memory"); + } else { + char savednamestr[DNS_NAME_FORMATSIZE]; + dns_name_format(savedname, savednamestr, + sizeof savednamestr); + if (!dns_name_equal(savedname, dst_key_name(key)) != 0) + fatal("all keys must have the same owner - %s " + "and %s do not match", + savednamestr, namestr); + } + if (output == NULL) { + output = isc_mem_allocate(mctx, + strlen("keyset-") + + strlen(namestr) + 1); + if (output == NULL) + fatal("out of memory"); + strcpy(output, "keyset-"); + strcat(output, namestr); + } + if (domain == NULL) { + dns_fixedname_init(&fdomain); + domain = dns_fixedname_name(&fdomain); + dns_name_copy(dst_key_name(key), domain, NULL); + } + if (dst_key_iszonekey(key)) { + dst_key_t *zonekey = NULL; + result = dst_key_fromnamedfile(argv[i], + DST_TYPE_PUBLIC | + DST_TYPE_PRIVATE, + mctx, &zonekey); + if (result != ISC_R_SUCCESS) + fatal("failed to read private key %s: %s", + argv[i], isc_result_totext(result)); + if (!zonekey_on_list(zonekey)) { + keynode = isc_mem_get(mctx, + sizeof (keynode_t)); + if (keynode == NULL) + fatal("out of memory"); + keynode->key = zonekey; + ISC_LIST_INITANDAPPEND(keylist, keynode, link); + } else + dst_key_free(&zonekey); + } + rdata = isc_mem_get(mctx, sizeof(dns_rdata_t)); + if (rdata == NULL) + fatal("out of memory"); + dns_rdata_init(rdata); + data = isc_mem_get(mctx, BUFSIZE); + if (data == NULL) + fatal("out of memory"); + isc_buffer_init(&b, data, BUFSIZE); + result = dst_key_todns(key, &b); + if (result != ISC_R_SUCCESS) + fatal("failed to convert key %s to a DNS KEY: %s", + argv[i], isc_result_totext(result)); + isc_buffer_usedregion(&b, &r); + dns_rdata_fromregion(rdata, rdatalist.rdclass, + dns_rdatatype_key, &r); + if (!rdata_on_list(rdata, &rdatalist)) + ISC_LIST_APPEND(rdatalist.rdata, rdata, link); + else { + isc_mem_put(mctx, data, BUFSIZE); + isc_mem_put(mctx, rdata, sizeof *rdata); + } + dst_key_free(&key); + } + + dns_rdataset_init(&rdataset); + result = dns_rdatalist_tordataset(&rdatalist, &rdataset); + check_result(result, "dns_rdatalist_tordataset()"); + + dns_rdatalist_init(&sigrdatalist); + sigrdatalist.rdclass = rdatalist.rdclass; + sigrdatalist.type = dns_rdatatype_sig; + sigrdatalist.covers = dns_rdatatype_key; + sigrdatalist.ttl = ttl; + + if (ISC_LIST_EMPTY(keylist)) + fprintf(stderr, + "%s: no private zone key found; not self-signing\n", + program); + for (keynode = ISC_LIST_HEAD(keylist); + keynode != NULL; + keynode = ISC_LIST_NEXT(keynode, link)) + { + rdata = isc_mem_get(mctx, sizeof(dns_rdata_t)); + if (rdata == NULL) + fatal("out of memory"); + dns_rdata_init(rdata); + data = isc_mem_get(mctx, BUFSIZE); + if (data == NULL) + fatal("out of memory"); + isc_buffer_init(&b, data, BUFSIZE); + result = dns_dnssec_sign(domain, &rdataset, keynode->key, + &starttime, &endtime, mctx, &b, + rdata); + isc_entropy_stopcallbacksources(ectx); + if (result != ISC_R_SUCCESS) { + char keystr[KEY_FORMATSIZE]; + key_format(keynode->key, keystr, sizeof keystr); + fatal("failed to sign keyset with key %s: %s", + keystr, isc_result_totext(result)); + } + if (tryverify) { + result = dns_dnssec_verify(domain, &rdataset, + keynode->key, ISC_TRUE, + mctx, rdata); + if (result != ISC_R_SUCCESS) { + char keystr[KEY_FORMATSIZE]; + key_format(keynode->key, keystr, sizeof keystr); + fatal("signature from key '%s' failed to " + "verify: %s", + keystr, isc_result_totext(result)); + } + } + ISC_LIST_APPEND(sigrdatalist.rdata, rdata, link); + dns_rdataset_init(&sigrdataset); + result = dns_rdatalist_tordataset(&sigrdatalist, &sigrdataset); + check_result(result, "dns_rdatalist_tordataset()"); + } + + db = NULL; + result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone, + rdataset.rdclass, 0, NULL, &db); + if (result != ISC_R_SUCCESS) { + char domainstr[DNS_NAME_FORMATSIZE]; + dns_name_format(domain, domainstr, sizeof domainstr); + fatal("failed to create a database for %s", domainstr); + } + + version = NULL; + dns_db_newversion(db, &version); + + node = NULL; + result = dns_db_findnode(db, domain, ISC_TRUE, &node); + check_result(result, "dns_db_findnode()"); + + dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL); + if (!ISC_LIST_EMPTY(keylist)) + dns_db_addrdataset(db, node, version, 0, &sigrdataset, 0, + NULL); + + dns_db_detachnode(db, &node); + dns_db_closeversion(db, &version, ISC_TRUE); + result = dns_db_dump(db, version, output); + if (result != ISC_R_SUCCESS) { + char domainstr[DNS_NAME_FORMATSIZE]; + dns_name_format(domain, domainstr, sizeof domainstr); + fatal("failed to write database for %s to %s", + domainstr, output); + } + + printf("%s\n", output); + + dns_db_detach(&db); + + dns_rdataset_disassociate(&rdataset); + while (!ISC_LIST_EMPTY(rdatalist.rdata)) { + rdata = ISC_LIST_HEAD(rdatalist.rdata); + ISC_LIST_UNLINK(rdatalist.rdata, rdata, link); + isc_mem_put(mctx, rdata->data, BUFSIZE); + isc_mem_put(mctx, rdata, sizeof *rdata); + } + while (!ISC_LIST_EMPTY(sigrdatalist.rdata)) { + rdata = ISC_LIST_HEAD(sigrdatalist.rdata); + ISC_LIST_UNLINK(sigrdatalist.rdata, rdata, link); + isc_mem_put(mctx, rdata->data, BUFSIZE); + isc_mem_put(mctx, rdata, sizeof *rdata); + } + + while (!ISC_LIST_EMPTY(keylist)) { + keynode = ISC_LIST_HEAD(keylist); + ISC_LIST_UNLINK(keylist, keynode, link); + dst_key_free(&keynode->key); + isc_mem_put(mctx, keynode, sizeof(keynode_t)); + } + + if (savedname != NULL) { + dns_name_free(savedname, mctx); + isc_mem_put(mctx, savedname, sizeof(dns_name_t)); + } + + cleanup_logging(&log); + cleanup_entropy(&ectx); + + isc_mem_free(mctx, output); + dst_lib_destroy(); + if (verbose > 10) + isc_mem_stats(mctx, stdout); + isc_mem_destroy(&mctx); + return (0); +} diff --git a/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-makekeyset.html b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-makekeyset.html new file mode 100644 index 0000000000..64c4c20ba9 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-makekeyset.html @@ -0,0 +1,407 @@ + + + + +dnssec-makekeyset

dnssec-makekeyset

Name

dnssec-makekeyset -- DNSSEC zone signing tool

Synopsis

dnssec-makekeyset [-a] [-s start-time] [-e end-time] [-h] [-p] [-r randomdev] [-tttl] [-v level] {key...}

DESCRIPTION

dnssec-makekeyset generates a key set from one + or more keys created by dnssec-keygen. It creates + a file containing a KEY record for each key, and self-signs the key + set with each zone key. The output file is of the form + keyset-nnnn., where nnnn + is the zone name. +

OPTIONS

-a

Verify all generated signatures. +

-s start-time

Specify the date and time when the generated SIG 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 is used. +

-e end-time

Specify the date and time when the generated SIG 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. +

-h

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

-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 ttl

Specify the TTL (time to live) of the KEY and SIG records. + The default is 3600 seconds. +

-v level

Sets the debugging level. +

key

The list of keys to be included in the keyset file. These keys + are expressed in the form Knnnn.+aaa+iiiii + as generated by dnssec-keygen. +

EXAMPLE

The following command generates a keyset containing the DSA key for + example.com generated in the + dnssec-keygen man page. +

dnssec-makekeyset -t 86400 -s 20000701120000 -e +2592000 Kexample.com.+003+26160 +

In this example, dnssec-makekeyset creates + the file keyset-example.com.. This file + contains the specified key and a self-generated signature. +

The DNS administrator for example.com could + send keyset-example.com. to the DNS + administrator for .com for signing, if the + .com zone is DNSSEC-aware and the administrators of the two zones + have some mechanism for authenticating each other and exchanging + the keys and signatures securely. +

SEE ALSO

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

AUTHOR

Internet Systems Consortium +

diff --git a/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signkey.8 b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signkey.8 new file mode 100644 index 0000000000..34b7df0b2a --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signkey.8 @@ -0,0 +1,108 @@ +.\" Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2000, 2001, 2003 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: dnssec-signkey.8,v 1.18.2.3 2004/06/03 05:21:11 marka Exp $ +.\" +.TH "DNSSEC-SIGNKEY" "8" "June 30, 2000" "BIND9" "" +.SH NAME +dnssec-signkey \- DNSSEC key set signing tool +.SH SYNOPSIS +.sp +\fBdnssec-signkey\fR [ \fB-a\fR ] [ \fB-c \fIclass\fB\fR ] [ \fB-s \fIstart-time\fB\fR ] [ \fB-e \fIend-time\fB\fR ] [ \fB-h\fR ] [ \fB-p\fR ] [ \fB-r \fIrandomdev\fB\fR ] [ \fB-v \fIlevel\fB\fR ] \fBkeyset\fR \fBkey\fR\fI...\fR +.SH "DESCRIPTION" +.PP +\fBdnssec-signkey\fR signs a keyset. Typically +the keyset will be for a child zone, and will have been generated +by \fBdnssec-makekeyset\fR. The child zone's keyset +is signed with the zone keys for its parent zone. The output file +is of the form \fIsignedkey-nnnn.\fR, where +\fInnnn\fR is the zone name. +.SH "OPTIONS" +.TP +\fB-a\fR +Verify all generated signatures. +.TP +\fB-c \fIclass\fB\fR +Specifies the DNS class of the key sets. +.TP +\fB-s \fIstart-time\fB\fR +Specify the date and time when the generated SIG 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 is used. +.TP +\fB-e \fIend-time\fB\fR +Specify the date and time when the generated SIG 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. +.TP +\fB-h\fR +Prints a short summary of the options and arguments to +\fBdnssec-signkey\fR. +.TP +\fB-p\fR +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. +.TP +\fB-r \fIrandomdev\fB\fR +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. +.TP +\fB-v \fIlevel\fB\fR +Sets the debugging level. +.TP +\fBkeyset\fR +The file containing the child's keyset. +.TP +\fBkey\fR +The keys used to sign the child's keyset. +.SH "EXAMPLE" +.PP +The DNS administrator for a DNSSEC-aware \fB.com\fR +zone would use the following command to sign the +\fIkeyset\fR file for \fBexample.com\fR +created by \fBdnssec-makekeyset\fR with a key generated +by \fBdnssec-keygen\fR: +.PP +\fBdnssec-signkey keyset-example.com. Kcom.+003+51944\fR +.PP +In this example, \fBdnssec-signkey\fR creates +the file \fIsignedkey-example.com.\fR, which +contains the \fBexample.com\fR keys and the +signatures by the \fB.com\fR keys. +.SH "SEE ALSO" +.PP +\fBdnssec-keygen\fR(8), +\fBdnssec-makekeyset\fR(8), +\fBdnssec-signzone\fR(8). +.SH "AUTHOR" +.PP +Internet Systems Consortium diff --git a/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signkey.c b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signkey.c new file mode 100644 index 0000000000..e687e316d0 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signkey.c @@ -0,0 +1,471 @@ +/* + * Portions Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2000, 2001, 2003 Internet Software Consortium. + * Portions Copyright (C) 1995-2000 by Network Associates, 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 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-signkey.c,v 1.50.2.4 2004/03/09 06:09:15 marka Exp $ */ + +#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-signkey"; +int verbose; + +#define BUFSIZE 2048 + +typedef struct keynode keynode_t; +struct keynode { + dst_key_t *key; + isc_boolean_t verified; + ISC_LINK(keynode_t) link; +}; +typedef ISC_LIST(keynode_t) keylist_t; + +static isc_stdtime_t starttime = 0, endtime = 0, now; + +static isc_mem_t *mctx = NULL; +static isc_entropy_t *ectx = NULL; +static keylist_t keylist; + +static void +usage(void) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\t%s [options] keyset keys\n", program); + + fprintf(stderr, "\n"); + + fprintf(stderr, "Options: (default value in parenthesis) \n"); + fprintf(stderr, "\t-a\n"); + fprintf(stderr, "\t\tverify generated signatures\n"); + fprintf(stderr, "\t-c class (IN)\n"); + fprintf(stderr, "\t-s YYYYMMDDHHMMSS|+offset:\n"); + fprintf(stderr, "\t\tSIG start time - absolute|offset (from keyset)\n"); + fprintf(stderr, "\t-e YYYYMMDDHHMMSS|+offset|\"now\"+offset]:\n"); + fprintf(stderr, "\t\tSIG end time - absolute|from start|from now " + "(from keyset)\n"); + fprintf(stderr, "\t-v level:\n"); + fprintf(stderr, "\t\tverbose level (0)\n"); + fprintf(stderr, "\t-p\n"); + fprintf(stderr, "\t\tuse pseudorandom data (faster but less secure)\n"); + fprintf(stderr, "\t-r randomdev:\n"); + fprintf(stderr, "\t\ta file containing random data\n"); + + fprintf(stderr, "\n"); + + fprintf(stderr, "keyset:\n"); + fprintf(stderr, "\tfile with keyset to be signed (keyset-)\n"); + fprintf(stderr, "keys:\n"); + fprintf(stderr, "\tkeyfile (Kname+alg+tag)\n"); + + fprintf(stderr, "\n"); + fprintf(stderr, "Output:\n"); + fprintf(stderr, "\tsigned keyset (signedkey-)\n"); + exit(0); +} + +static void +loadkeys(dns_name_t *name, dns_rdataset_t *rdataset) { + dst_key_t *key; + dns_rdata_t rdata = DNS_RDATA_INIT; + keynode_t *keynode; + isc_result_t result; + + ISC_LIST_INIT(keylist); + result = dns_rdataset_first(rdataset); + check_result(result, "dns_rdataset_first"); + for (; result == ISC_R_SUCCESS; result = dns_rdataset_next(rdataset)) { + dns_rdata_reset(&rdata); + dns_rdataset_current(rdataset, &rdata); + key = NULL; + result = dns_dnssec_keyfromrdata(name, &rdata, mctx, &key); + if (result != ISC_R_SUCCESS) + continue; + if (!dst_key_iszonekey(key)) + continue; + keynode = isc_mem_get(mctx, sizeof (keynode_t)); + if (keynode == NULL) + fatal("out of memory"); + keynode->key = key; + keynode->verified = ISC_FALSE; + ISC_LIST_INITANDAPPEND(keylist, keynode, link); + } + if (result != ISC_R_NOMORE) + fatal("failure traversing key list"); +} + +static dst_key_t * +findkey(dns_rdata_sig_t *sig) { + keynode_t *keynode; + for (keynode = ISC_LIST_HEAD(keylist); + keynode != NULL; + keynode = ISC_LIST_NEXT(keynode, link)) + { + if (dst_key_id(keynode->key) == sig->keyid && + dst_key_alg(keynode->key) == sig->algorithm) { + keynode->verified = ISC_TRUE; + return (keynode->key); + } + } + fatal("signature generated by non-zone or missing key"); + return (NULL); +} + +int +main(int argc, char *argv[]) { + int i, ch; + char *startstr = NULL, *endstr = NULL, *classname = NULL; + char tdomain[1025]; + dns_fixedname_t fdomain; + dns_name_t *domain; + char *output = NULL; + char *endp; + unsigned char *data; + char *randomfile = NULL; + dns_db_t *db; + dns_dbnode_t *node; + dns_dbversion_t *version; + dns_dbiterator_t *dbiter; + dns_rdatasetiter_t *rdsiter; + dst_key_t *key = NULL; + dns_rdata_t *rdata; + dns_rdata_t sigrdata = DNS_RDATA_INIT; + dns_rdatalist_t sigrdatalist; + dns_rdataset_t rdataset, sigrdataset, newsigrdataset; + dns_rdata_sig_t sig; + isc_result_t result; + isc_buffer_t b; + isc_textregion_t tr; + isc_log_t *log = NULL; + keynode_t *keynode; + isc_boolean_t pseudorandom = ISC_FALSE; + unsigned int eflags; + dns_rdataclass_t rdclass; + static isc_boolean_t tryverify = ISC_FALSE; + + result = isc_mem_create(0, 0, &mctx); + check_result(result, "isc_mem_create()"); + + dns_result_register(); + + while ((ch = isc_commandline_parse(argc, argv, "ac:s:e:pr:v:h")) != -1) + { + switch (ch) { + case 'a': + tryverify = ISC_TRUE; + break; + case 'c': + classname = isc_commandline_argument; + break; + + case 's': + startstr = isc_commandline_argument; + break; + + case 'e': + endstr = isc_commandline_argument; + break; + + case 'p': + pseudorandom = ISC_TRUE; + break; + + case 'r': + randomfile = isc_commandline_argument; + break; + + case 'v': + endp = NULL; + verbose = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') + fatal("verbose level must be numeric"); + break; + + case 'h': + default: + usage(); + + } + } + + argc -= isc_commandline_index; + argv += isc_commandline_index; + + if (argc < 2) + usage(); + + if (classname != NULL) { + tr.base = classname; + tr.length = strlen(classname); + result = dns_rdataclass_fromtext(&rdclass, &tr); + if (result != ISC_R_SUCCESS) + fatal("unknown class %s",classname); + } else + rdclass = dns_rdataclass_in; + + setup_entropy(mctx, randomfile, &ectx); + eflags = ISC_ENTROPY_BLOCKING; + if (!pseudorandom) + eflags |= ISC_ENTROPY_GOODONLY; + result = dst_lib_init(mctx, ectx, eflags); + if (result != ISC_R_SUCCESS) + fatal("could not initialize dst: %s", + isc_result_totext(result)); + + isc_stdtime_get(&now); + + if ((startstr == NULL || endstr == NULL) && + !(startstr == NULL && endstr == NULL)) + fatal("if -s or -e is specified, both must be"); + + setup_logging(verbose, mctx, &log); + + if (strlen(argv[0]) < 8U || strncmp(argv[0], "keyset-", 7) != 0) + fatal("keyset file '%s' must start with keyset-", argv[0]); + + db = NULL; + result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone, + rdclass, 0, NULL, &db); + check_result(result, "dns_db_create()"); + + result = dns_db_load(db, argv[0]); + if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) + fatal("failed to load database from '%s': %s", argv[0], + isc_result_totext(result)); + + dns_fixedname_init(&fdomain); + domain = dns_fixedname_name(&fdomain); + + dbiter = NULL; + result = dns_db_createiterator(db, ISC_FALSE, &dbiter); + check_result(result, "dns_db_createiterator()"); + + result = dns_dbiterator_first(dbiter); + check_result(result, "dns_dbiterator_first()"); + while (result == ISC_R_SUCCESS) { + node = NULL; + dns_dbiterator_current(dbiter, &node, domain); + rdsiter = NULL; + result = dns_db_allrdatasets(db, node, NULL, 0, &rdsiter); + check_result(result, "dns_db_allrdatasets()"); + result = dns_rdatasetiter_first(rdsiter); + dns_rdatasetiter_destroy(&rdsiter); + if (result == ISC_R_SUCCESS) + break; + dns_db_detachnode(db, &node); + result = dns_dbiterator_next(dbiter); + } + dns_dbiterator_destroy(&dbiter); + if (result != ISC_R_SUCCESS) + fatal("failed to find data in keyset file"); + + isc_buffer_init(&b, tdomain, sizeof(tdomain) - 1); + result = dns_name_tofilenametext(domain, ISC_FALSE, &b); + check_result(result, "dns_name_tofilenametext()"); + isc_buffer_putuint8(&b, 0); + + output = isc_mem_allocate(mctx, + strlen("signedkey-") + strlen(tdomain) + 1); + if (output == NULL) + fatal("out of memory"); + strcpy(output, "signedkey-"); + strcat(output, tdomain); + + version = NULL; + dns_db_newversion(db, &version); + + dns_rdataset_init(&rdataset); + dns_rdataset_init(&sigrdataset); + result = dns_db_findrdataset(db, node, version, dns_rdatatype_key, 0, + 0, &rdataset, &sigrdataset); + if (result != ISC_R_SUCCESS) { + char domainstr[DNS_NAME_FORMATSIZE]; + dns_name_format(domain, domainstr, sizeof domainstr); + fatal("failed to find rdataset '%s KEY': %s", + domainstr, isc_result_totext(result)); + } + + loadkeys(domain, &rdataset); + + if (!dns_rdataset_isassociated(&sigrdataset)) + fatal("no SIG KEY set present"); + + result = dns_rdataset_first(&sigrdataset); + check_result(result, "dns_rdataset_first()"); + do { + dns_rdataset_current(&sigrdataset, &sigrdata); + result = dns_rdata_tostruct(&sigrdata, &sig, mctx); + check_result(result, "dns_rdata_tostruct()"); + key = findkey(&sig); + result = dns_dnssec_verify(domain, &rdataset, key, + ISC_TRUE, mctx, &sigrdata); + if (result != ISC_R_SUCCESS) { + char keystr[KEY_FORMATSIZE]; + key_format(key, keystr, sizeof keystr); + fatal("signature by key '%s' did not verify: %s", + keystr, isc_result_totext(result)); + } + dns_rdata_reset(&sigrdata); + dns_rdata_freestruct(&sig); + result = dns_rdataset_next(&sigrdataset); + } while (result == ISC_R_SUCCESS); + + if (startstr != NULL) { + starttime = strtotime(startstr, now, now); + endtime = strtotime(endstr, now, starttime); + } else { + starttime = sig.timesigned; + endtime = sig.timeexpire; + } + + + for (keynode = ISC_LIST_HEAD(keylist); + keynode != NULL; + keynode = ISC_LIST_NEXT(keynode, link)) + if (!keynode->verified) + fatal("Not all zone keys self signed the key set"); + + result = dns_rdataset_first(&sigrdataset); + check_result(result, "dns_rdataset_first()"); + dns_rdataset_current(&sigrdataset, &sigrdata); + result = dns_rdata_tostruct(&sigrdata, &sig, mctx); + check_result(result, "dns_rdata_tostruct()"); + + dns_rdataset_disassociate(&sigrdataset); + + argc -= 1; + argv += 1; + + dns_rdatalist_init(&sigrdatalist); + sigrdatalist.rdclass = rdataset.rdclass; + sigrdatalist.type = dns_rdatatype_sig; + sigrdatalist.covers = dns_rdatatype_key; + sigrdatalist.ttl = rdataset.ttl; + + for (i = 0; i < argc; i++) { + key = NULL; + result = dst_key_fromnamedfile(argv[i], + DST_TYPE_PUBLIC | + DST_TYPE_PRIVATE, + mctx, &key); + if (result != ISC_R_SUCCESS) + fatal("failed to read key %s from disk: %s", + argv[i], isc_result_totext(result)); + + rdata = isc_mem_get(mctx, sizeof(dns_rdata_t)); + if (rdata == NULL) + fatal("out of memory"); + dns_rdata_init(rdata); + data = isc_mem_get(mctx, BUFSIZE); + if (data == NULL) + fatal("out of memory"); + isc_buffer_init(&b, data, BUFSIZE); + result = dns_dnssec_sign(domain, &rdataset, key, + &starttime, &endtime, + mctx, &b, rdata); + isc_entropy_stopcallbacksources(ectx); + if (result != ISC_R_SUCCESS) { + char keystr[KEY_FORMATSIZE]; + key_format(key, keystr, sizeof keystr); + fatal("key '%s' failed to sign data: %s", + keystr, isc_result_totext(result)); + } + if (tryverify) { + result = dns_dnssec_verify(domain, &rdataset, key, + ISC_TRUE, mctx, rdata); + if (result != ISC_R_SUCCESS) { + char keystr[KEY_FORMATSIZE]; + key_format(key, keystr, sizeof keystr); + fatal("signature from key '%s' failed to " + "verify: %s", + keystr, isc_result_totext(result)); + } + } + ISC_LIST_APPEND(sigrdatalist.rdata, rdata, link); + dst_key_free(&key); + } + + dns_rdataset_init(&newsigrdataset); + result = dns_rdatalist_tordataset(&sigrdatalist, &newsigrdataset); + check_result (result, "dns_rdatalist_tordataset()"); + + dns_db_addrdataset(db, node, version, 0, &newsigrdataset, 0, NULL); + check_result (result, "dns_db_addrdataset()"); + + dns_db_detachnode(db, &node); + dns_db_closeversion(db, &version, ISC_TRUE); + result = dns_db_dump(db, version, output); + if (result != ISC_R_SUCCESS) + fatal("failed to write database to '%s': %s", + output, isc_result_totext(result)); + + printf("%s\n", output); + + dns_rdataset_disassociate(&rdataset); + dns_rdataset_disassociate(&newsigrdataset); + + dns_rdata_freestruct(&sig); + + while (!ISC_LIST_EMPTY(sigrdatalist.rdata)) { + rdata = ISC_LIST_HEAD(sigrdatalist.rdata); + ISC_LIST_UNLINK(sigrdatalist.rdata, rdata, link); + isc_mem_put(mctx, rdata->data, BUFSIZE); + isc_mem_put(mctx, rdata, sizeof *rdata); + } + + dns_db_detach(&db); + + while (!ISC_LIST_EMPTY(keylist)) { + keynode = ISC_LIST_HEAD(keylist); + ISC_LIST_UNLINK(keylist, keynode, link); + dst_key_free(&keynode->key); + isc_mem_put(mctx, keynode, sizeof(keynode_t)); + } + + cleanup_logging(&log); + + isc_mem_free(mctx, output); + cleanup_entropy(&ectx); + dst_lib_destroy(); + if (verbose > 10) + isc_mem_stats(mctx, stdout); + isc_mem_destroy(&mctx); + return (0); +} diff --git a/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signkey.html b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signkey.html new file mode 100644 index 0000000000..78d3a3928a --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signkey.html @@ -0,0 +1,407 @@ + + + + +dnssec-signkey

dnssec-signkey

Name

dnssec-signkey -- DNSSEC key set signing tool

Synopsis

dnssec-signkey [-a] [-c class] [-s start-time] [-e end-time] [-h] [-p] [-r randomdev] [-v level] {keyset} {key...}

DESCRIPTION

dnssec-signkey signs a keyset. Typically + the keyset will be for a child zone, and will have been generated + by dnssec-makekeyset. The child zone's keyset + is signed with the zone keys for its parent zone. The output file + is of the form signedkey-nnnn., where + nnnn is the zone name. +

OPTIONS

-a

Verify all generated signatures. +

-c class

Specifies the DNS class of the key sets. +

-s start-time

Specify the date and time when the generated SIG 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 is used. +

-e end-time

Specify the date and time when the generated SIG 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. +

-h

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

-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. +

-v level

Sets the debugging level. +

keyset

The file containing the child's keyset. +

key

The keys used to sign the child's keyset. +

EXAMPLE

The DNS administrator for a DNSSEC-aware .com + zone would use the following command to sign the + keyset file for example.com + created by dnssec-makekeyset with a key generated + by dnssec-keygen: +

dnssec-signkey keyset-example.com. Kcom.+003+51944 +

In this example, dnssec-signkey creates + the file signedkey-example.com., which + contains the example.com keys and the + signatures by the .com keys. +

SEE ALSO

dnssec-keygen(8), + dnssec-makekeyset(8), + dnssec-signzone(8). +

AUTHOR

Internet Systems Consortium +

diff --git a/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signzone.8 b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signzone.8 new file mode 100644 index 0000000000..72d766b4a1 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signzone.8 @@ -0,0 +1,155 @@ +.\" Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2000, 2001, 2003 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: dnssec-signzone.8,v 1.23.2.4 2004/06/03 05:21:12 marka Exp $ +.\" +.TH "DNSSEC-SIGNZONE" "8" "June 30, 2000" "BIND9" "" +.SH NAME +dnssec-signzone \- DNSSEC zone signing tool +.SH SYNOPSIS +.sp +\fBdnssec-signzone\fR [ \fB-a\fR ] [ \fB-c \fIclass\fB\fR ] [ \fB-d \fIdirectory\fB\fR ] [ \fB-s \fIstart-time\fB\fR ] [ \fB-e \fIend-time\fB\fR ] [ \fB-f \fIoutput-file\fB\fR ] [ \fB-h\fR ] [ \fB-i \fIinterval\fB\fR ] [ \fB-n \fInthreads\fB\fR ] [ \fB-o \fIorigin\fB\fR ] [ \fB-p\fR ] [ \fB-r \fIrandomdev\fB\fR ] [ \fB-t\fR ] [ \fB-v \fIlevel\fB\fR ] \fBzonefile\fR [ \fBkey\fR\fI...\fR ] +.SH "DESCRIPTION" +.PP +\fBdnssec-signzone\fR signs a zone. It generates NXT +and SIG records and produces a signed version of the zone. If there +is a \fIsignedkey\fR file from the zone's parent, +the parent's signatures will be incorporated into the generated +signed zone file. 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 +\fIsignedkey\fR file for each child zone. +.SH "OPTIONS" +.TP +\fB-a\fR +Verify all generated signatures. +.TP +\fB-c \fIclass\fB\fR +Specifies the DNS class of the zone. +.TP +\fB-d \fIdirectory\fB\fR +Look for \fIsignedkey\fR files in +\fBdirectory\fR as the directory +.TP +\fB-s \fIstart-time\fB\fR +Specify the date and time when the generated SIG 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 is used. +.TP +\fB-e \fIend-time\fB\fR +Specify the date and time when the generated SIG 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. +.TP +\fB-f \fIoutput-file\fB\fR +The name of the output file containing the signed zone. The +default is to append \fI.signed\fR to the +input file. +.TP +\fB-h\fR +Prints a short summary of the options and arguments to +\fBdnssec-signzone\fR. +.TP +\fB-i \fIinterval\fB\fR +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 SIG 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 +\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 SIG records +are due to expire in less than 7.5 days, they would be +replaced. +.TP +\fB-n \fIncpus\fB\fR +Specifies the number of threads to use. By default, one +thread is started for each detected CPU. +.TP +\fB-o \fIorigin\fB\fR +The zone origin. If not specified, the name of the zone file +is assumed to be the origin. +.TP +\fB-p\fR +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. +.TP +\fB-r \fIrandomdev\fB\fR +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. +.TP +\fB-t\fR +Print statistics at completion. +.TP +\fB-v \fIlevel\fB\fR +Sets the debugging level. +.TP +\fBzonefile\fR +The file containing the zone to be signed. +Sets the debugging level. +.TP +\fBkey\fR +The keys used to sign the zone. If no keys are specified, the +default all zone keys that have private key files in the +current directory. +.SH "EXAMPLE" +.PP +The following command signs the \fBexample.com\fR +zone with the DSA key generated in the \fBdnssec-keygen\fR +man page. The zone's keys must be in the zone. If there are +\fIsignedkey\fR files associated with this zone +or any child zones, they must be in the current directory. +\fBexample.com\fR, the following command would be +issued: +.PP +\fBdnssec-signzone -o example.com db.example.com Kexample.com.+003+26160\fR +.PP +The command would print a string of the form: +.PP +In this 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. +.SH "SEE ALSO" +.PP +\fBdnssec-keygen\fR(8), +\fBdnssec-signkey\fR(8), +\fIBIND 9 Administrator Reference Manual\fR, +\fIRFC 2535\fR. +.SH "AUTHOR" +.PP +Internet Systems Consortium diff --git a/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signzone.c b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signzone.c new file mode 100644 index 0000000000..ca7b9817c1 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signzone.c @@ -0,0 +1,1880 @@ +/* + * Portions Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 1999-2001, 2003 Internet Software Consortium. + * Portions Copyright (C) 1995-2000 by Network Associates, 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 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.139.2.5 2004/04/15 02:16:24 marka Exp $ */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "dnssectool.h" + +const char *program = "dnssec-signzone"; +int verbose; + +#define BUFSIZE 2048 + +typedef struct signer_key_struct signer_key_t; + +struct signer_key_struct { + dst_key_t *key; + isc_boolean_t isdefault; + 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) + +typedef struct signer_event sevent_t; +struct signer_event { + ISC_EVENT_COMMON(sevent_t); + dns_fixedname_t *fname; + dns_fixedname_t *fnextname; + 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 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 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_name_t *gorigin; /* The database origin */ +static dns_dbnode_t *gnode = NULL; /* The "current" database node */ +static dns_name_t *lastzonecut; +static isc_task_t *master = NULL; +static unsigned int ntasks = 0; +static isc_boolean_t shuttingdown = ISC_FALSE, finished = ISC_FALSE; +static unsigned int assigned = 0, completed = 0; +static isc_boolean_t nokeys = ISC_FALSE; +static isc_boolean_t removefile = ISC_FALSE; + +#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 signer_key_t * +newkeystruct(dst_key_t *dstkey, isc_boolean_t isdefault) { + signer_key_t *key; + + key = isc_mem_get(mctx, sizeof(signer_key_t)); + if (key == NULL) + fatal("out of memory"); + key->key = dstkey; + key->isdefault = isdefault; + key->position = keycount++; + ISC_LINK_INIT(key, link); + return (key); +} + +static void +signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dns_rdata_t *rdata, + dst_key_t *key, isc_buffer_t *b) +{ + isc_result_t result; + + result = dns_dnssec_sign(name, rdataset, key, &starttime, &endtime, + mctx, b, rdata); + isc_entropy_stopcallbacksources(ectx); + if (result != ISC_R_SUCCESS) { + char keystr[KEY_FORMATSIZE]; + key_format(key, keystr, sizeof keystr); + fatal("key '%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, rdata); + if (result == ISC_R_SUCCESS) { + vbprintf(3, "\tsignature verified\n"); + INCSTAT(nverified); + } else { + vbprintf(3, "\tsignature failed to verify\n"); + INCSTAT(nverifyfailed); + } + } +} + +static inline isc_boolean_t +issigningkey(signer_key_t *key) { + return (key->isdefault); +} + +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 SIG, 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_sig_t *sig) { + isc_result_t result; + dst_key_t *pubkey = NULL, *privkey = NULL; + signer_key_t *key; + + key = ISC_LIST_HEAD(keylist); + while (key != NULL) { + if (sig->keyid == dst_key_id(key->key) && + sig->algorithm == dst_key_alg(key->key) && + dns_name_equal(&sig->signer, dst_key_name(key->key))) + return key; + key = ISC_LIST_NEXT(key, link); + } + + result = dst_key_fromfile(&sig->signer, sig->keyid, sig->algorithm, + DST_TYPE_PUBLIC, NULL, mctx, &pubkey); + if (result != ISC_R_SUCCESS) + return (NULL); + + result = dst_key_fromfile(&sig->signer, sig->keyid, sig->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 SIG + * and can't find the signing key that we expect to find, we drop the sig. + * 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_key, 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 KEY' 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 *sig) +{ + isc_result_t result; + result = dns_dnssec_verify(name, set, key->key, ISC_FALSE, mctx, sig); + 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 SIG should + * be dropped or retained, and then determines if any new SIGs need to + * be generated. + */ +static void +signset(dns_diff_t *diff, 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_sig_t sig; + 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_sig, + 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 SIG %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, &sig, NULL); + check_result(result, "dns_rdata_tostruct"); + + expired = ISC_TF(now + cycle > sig.timeexpire); + future = ISC_TF(now < sig.timesigned); + + key = keythatsigned(&sig); + sig_format(&sig, sigstr, sizeof sigstr); + + if (sig.timesigned > sig.timeexpire) { + /* sig is dropped and not replaced */ + vbprintf(2, "\tsig by %s dropped - " + "invalid validity period\n", + sigstr); + } else if (key == NULL && !future && + expecttofindkey(&sig.signer)) + { + /* sig is dropped and not replaced */ + vbprintf(2, "\tsig by %s dropped - " + "private key not found\n", + sigstr); + } else if (key == NULL || future) { + vbprintf(2, "\tsig by %s %s - key 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, "\tsig by %s retained\n", sigstr); + keep = ISC_TRUE; + wassignedby[key->position] = ISC_TRUE; + nowsignedby[key->position] = ISC_TRUE; + } else { + vbprintf(2, "\tsig 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, "\tsig by %s retained\n", sigstr); + keep = ISC_TRUE; + wassignedby[key->position] = ISC_TRUE; + nowsignedby[key->position] = ISC_TRUE; + } else { + vbprintf(2, "\tsig by %s dropped - %s\n", + sigstr, + expired ? "expired" : + "failed to verify"); + wassignedby[key->position] = ISC_TRUE; + } + } else if (!expired) { + vbprintf(2, "\tsig by %s retained\n", sigstr); + keep = ISC_TRUE; + } else { + vbprintf(2, "\tsig by %s expired\n", sigstr); + } + + if (keep) { + nowsignedby[key->position] = ISC_TRUE; + INCSTAT(nretained); + } 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(diff, &tuple); + INCSTAT(ndropped); + } + + if (resign) { + isc_buffer_t b; + dns_rdata_t trdata = DNS_RDATA_INIT; + unsigned char array[BUFSIZE]; + char keystr[KEY_FORMATSIZE]; + + key_format(key->key, keystr, sizeof keystr); + vbprintf(1, "\tresigning with key %s\n", keystr); + isc_buffer_init(&b, array, sizeof(array)); + signwithkey(name, set, &trdata, key->key, &b); + nowsignedby[key->position] = ISC_TRUE; + tuple = NULL; + result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, + name, ttl, &trdata, + &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(diff, &tuple); + } + + dns_rdata_reset(&sigrdata); + dns_rdata_freestruct(&sig); + 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); + + key = ISC_LIST_HEAD(keylist); + while (key != NULL) { + if (key->isdefault && !nowsignedby[key->position]) { + isc_buffer_t b; + dns_rdata_t trdata = DNS_RDATA_INIT; + unsigned char array[BUFSIZE]; + char keystr[KEY_FORMATSIZE]; + + key_format(key->key, keystr, sizeof keystr); + vbprintf(1, "\tsigning with key %s\n", keystr); + isc_buffer_init(&b, array, sizeof(array)); + signwithkey(name, set, &trdata, key->key, &b); + tuple = NULL; + result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, + name, ttl, &trdata, + &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(diff, &tuple); + } + key = ISC_LIST_NEXT(key, link); + } + + isc_mem_put(mctx, wassignedby, arraysize * sizeof(isc_boolean_t)); + isc_mem_put(mctx, nowsignedby, arraysize * sizeof(isc_boolean_t)); +} + +/* Determine if a KEY set contains a null key */ +static isc_boolean_t +hasnullkey(dns_rdataset_t *rdataset) { + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_boolean_t found = ISC_FALSE; + + result = dns_rdataset_first(rdataset); + while (result == ISC_R_SUCCESS) { + dst_key_t *key = NULL; + + dns_rdata_reset(&rdata); + dns_rdataset_current(rdataset, &rdata); + result = dns_dnssec_keyfromrdata(dns_rootname, + &rdata, mctx, &key); + if (result != ISC_R_SUCCESS) + fatal("could not convert KEY into internal format: %s", + isc_result_totext(result)); + if (dst_key_isnullkey(key)) + found = ISC_TRUE; + dst_key_free(&key); + if (found == ISC_TRUE) + return (ISC_TRUE); + result = dns_rdataset_next(rdataset); + } + if (result != ISC_R_NOMORE) + fatal("failure looking for null keys"); + return (ISC_FALSE); +} + +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); +} + +/* + * Looks for signatures of the zone keys by the parent, and imports them + * if found. + */ +static void +importparentsig(dns_diff_t *diff, dns_name_t *name, dns_rdataset_t *set) { + dns_db_t *newdb = NULL; + dns_dbnode_t *newnode = NULL; + dns_rdataset_t newset, sigset; + dns_rdata_t rdata = DNS_RDATA_INIT, newrdata = DNS_RDATA_INIT; + isc_result_t result; + + dns_rdataset_init(&newset); + dns_rdataset_init(&sigset); + + opendb("signedkey-", name, dns_db_class(gdb), &newdb); + if (newdb == NULL) + return; + + result = dns_db_findnode(newdb, name, ISC_FALSE, &newnode); + if (result != ISC_R_SUCCESS) + goto failure; + result = dns_db_findrdataset(newdb, newnode, NULL, dns_rdatatype_key, + 0, 0, &newset, &sigset); + if (result != ISC_R_SUCCESS) + goto failure; + + if (!dns_rdataset_isassociated(&newset) || + !dns_rdataset_isassociated(&sigset)) + goto failure; + + if (dns_rdataset_count(set) != dns_rdataset_count(&newset)) { + result = DNS_R_BADDB; + goto failure; + } + + result = dns_rdataset_first(set); + check_result(result, "dns_rdataset_first()"); + for (; result == ISC_R_SUCCESS; result = dns_rdataset_next(set)) { + dns_rdataset_current(set, &rdata); + result = dns_rdataset_first(&newset); + check_result(result, "dns_rdataset_first()"); + for (; + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&newset)) + { + dns_rdataset_current(&newset, &newrdata); + if (dns_rdata_compare(&rdata, &newrdata) == 0) + break; + dns_rdata_reset(&newrdata); + } + dns_rdata_reset(&newrdata); + dns_rdata_reset(&rdata); + if (result != ISC_R_SUCCESS) + break; + } + if (result != ISC_R_NOMORE) + goto failure; + + vbprintf(2, "found the parent's signature of our zone key\n"); + + result = dns_rdataset_first(&sigset); + while (result == ISC_R_SUCCESS) { + dns_difftuple_t *tuple = NULL; + + dns_rdataset_current(&sigset, &rdata); + result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name, + sigset.ttl, &rdata, &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(diff, &tuple); + result = dns_rdataset_next(&sigset); + dns_rdata_reset(&rdata); + } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + + failure: + if (dns_rdataset_isassociated(&newset)) + dns_rdataset_disassociate(&newset); + if (dns_rdataset_isassociated(&sigset)) + dns_rdataset_disassociate(&sigset); + if (newnode != NULL) + dns_db_detachnode(newdb, &newnode); + if (newdb != NULL) + dns_db_detach(&newdb); + if (result != ISC_R_SUCCESS) + fatal("zone signedkey file is invalid or does not match zone"); +} + +/* + * Looks for our signatures of child keys. If present, inform the caller. + */ +static isc_boolean_t +haschildkey(dns_name_t *name) { + dns_db_t *newdb = NULL; + dns_dbnode_t *newnode = NULL; + dns_rdataset_t set, sigset; + dns_rdata_t sigrdata = DNS_RDATA_INIT; + isc_result_t result; + isc_boolean_t found = ISC_FALSE; + dns_rdata_sig_t sig; + signer_key_t *key; + + dns_rdataset_init(&set); + dns_rdataset_init(&sigset); + + opendb("signedkey-", name, dns_db_class(gdb), &newdb); + if (newdb == NULL) + return (ISC_FALSE); + + result = dns_db_findnode(newdb, name, ISC_FALSE, &newnode); + if (result != ISC_R_SUCCESS) + goto failure; + result = dns_db_findrdataset(newdb, newnode, NULL, dns_rdatatype_key, + 0, 0, &set, &sigset); + if (result != ISC_R_SUCCESS) + goto failure; + + if (!dns_rdataset_isassociated(&set) || + !dns_rdataset_isassociated(&sigset)) + goto failure; + + result = dns_rdataset_first(&sigset); + check_result(result, "dns_rdataset_first()"); + dns_rdata_init(&sigrdata); + for (; result == ISC_R_SUCCESS; result = dns_rdataset_next(&sigset)) { + dns_rdataset_current(&sigset, &sigrdata); + result = dns_rdata_tostruct(&sigrdata, &sig, NULL); + if (result != ISC_R_SUCCESS) + goto failure; + key = keythatsigned(&sig); + dns_rdata_freestruct(&sig); + if (key == NULL) { + char namestr[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namestr, sizeof namestr); + fprintf(stderr, + "creating KEY from signedkey file for %s: " + "%s\n", + namestr, isc_result_totext(result)); + goto failure; + } + result = dns_dnssec_verify(name, &set, key->key, + ISC_FALSE, mctx, &sigrdata); + if (result == ISC_R_SUCCESS) { + found = ISC_TRUE; + break; + } else { + char namestr[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namestr, sizeof namestr); + fprintf(stderr, + "verifying SIG in signedkey file for %s: %s\n", + namestr, isc_result_totext(result)); + } + dns_rdata_reset(&sigrdata); + } + + failure: + if (dns_rdataset_isassociated(&set)) + dns_rdataset_disassociate(&set); + if (dns_rdataset_isassociated(&sigset)) + dns_rdataset_disassociate(&sigset); + if (newnode != NULL) + dns_db_detachnode(newdb, &newnode); + if (newdb != NULL) + dns_db_detach(&newdb); + + return (found); +} + +/* + * There probably should be a dns_nxt_setbit, but it can get complicated if + * the length of the bit set needs to be increased. In this case, since the + * NXT bit is set and both SIG and KEY are less than NXT, the easy way works. + */ +static void +nxt_setbit(dns_rdataset_t *rdataset, dns_rdatatype_t type) { + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_nxt_t nxt; + + result = dns_rdataset_first(rdataset); + check_result(result, "dns_rdataset_first()"); + dns_rdataset_current(rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &nxt, NULL); + check_result(result, "dns_rdata_tostruct"); + set_bit(nxt.typebits, type, 1); + dns_rdata_freestruct(&nxt); +} + +static void +createnullkey(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, + dns_ttl_t ttl) +{ + unsigned char keydata[4]; + dns_rdata_t keyrdata = DNS_RDATA_INIT; + dns_rdata_key_t key; + dns_diff_t diff; + dns_difftuple_t *tuple = NULL; + isc_buffer_t b; + isc_result_t result; + char namestr[DNS_NAME_FORMATSIZE]; + + dns_name_format(name, namestr, sizeof namestr); + vbprintf(2, "adding null key at %s\n", namestr); + + key.common.rdclass = dns_db_class(db); + key.common.rdtype = dns_rdatatype_key; + ISC_LINK_INIT(&key.common, link); + key.mctx = NULL; + key.flags = DNS_KEYTYPE_NOKEY | DNS_KEYOWNER_ZONE; + key.protocol = DNS_KEYPROTO_DNSSEC; + key.algorithm = DNS_KEYALG_DSA; + key.datalen = 0; + key.data = NULL; + isc_buffer_init(&b, keydata, sizeof keydata); + result = dns_rdata_fromstruct(&keyrdata, dns_db_class(db), + dns_rdatatype_key, &key, &b); + if (result != ISC_R_SUCCESS) + fatal("failed to build null key"); + + dns_diff_init(mctx, &diff); + + result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name, ttl, + &keyrdata, &tuple); + check_result(result, "dns_difftuple_create"); + + dns_diff_append(&diff, &tuple); + + result = dns_diff_apply(&diff, db, version); + check_result(result, "dns_diff_apply"); + + dns_diff_clear(&diff); +} + +/* + * Signs all records at a name. This mostly just signs each set individually, + * but also adds the SIG bit to any NXTs 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 childkey = ISC_FALSE; + static int warnwild = 0; + isc_boolean_t atorigin; + isc_boolean_t neednullkey = ISC_FALSE; + dns_diff_t diff; + + if (dns_name_iswildcard(name)) { + char namestr[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namestr, sizeof namestr); + if (warnwild++ == 0) { + fprintf(stderr, "%s: warning: BIND 9 doesn't properly " + "handle wildcards in secure zones:\n", + program); + fprintf(stderr, "\t- wildcard nonexistence proof is " + "not generated by the server\n"); + fprintf(stderr, "\t- wildcard nonexistence proof is " + "not required by the resolver\n"); + } + fprintf(stderr, "%s: warning: wildcard name seen: %s\n", + program, namestr); + } + + atorigin = dns_name_equal(name, gorigin); + + /* + * If this is not the origin, determine if it's a delegation point. + */ + if (!atorigin) { + dns_rdataset_t nsset; + + dns_rdataset_init(&nsset); + result = dns_db_findrdataset(gdb, node, gversion, + dns_rdatatype_ns, 0, 0, &nsset, + NULL); + /* Is this a delegation point? */ + if (result == ISC_R_SUCCESS) { + isdelegation = ISC_TRUE; + dns_rdataset_disassociate(&nsset); + } + } + + /* + * If this is a delegation point, determine if we need to generate + * a null key. + */ + if (isdelegation) { + dns_rdataset_t keyset; + dns_ttl_t nullkeyttl; + + childkey = haschildkey(name); + neednullkey = ISC_TRUE; + nullkeyttl = zonettl; + + dns_rdataset_init(&keyset); + result = dns_db_findrdataset(gdb, node, gversion, + dns_rdatatype_key, 0, 0, &keyset, + NULL); + if (result == ISC_R_SUCCESS && childkey) { + char namestr[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namestr, sizeof namestr); + if (hasnullkey(&keyset)) { + fatal("%s has both a signedkey file and " + "null keys in the zone. Aborting.", + namestr); + } + vbprintf(2, "child key for %s found\n", namestr); + neednullkey = ISC_FALSE; + dns_rdataset_disassociate(&keyset); + } + else if (result == ISC_R_SUCCESS) { + if (hasnullkey(&keyset)) + neednullkey = ISC_FALSE; + nullkeyttl = keyset.ttl; + dns_rdataset_disassociate(&keyset); + } else if (childkey) { + char namestr[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namestr, sizeof namestr); + vbprintf(2, "child key for %s found\n", namestr); + neednullkey = ISC_FALSE; + } + + if (neednullkey) + createnullkey(gdb, gversion, name, nullkeyttl); + } + + /* + * Now iterate through the rdatasets. + */ + dns_diff_init(mctx, &diff); + dns_rdataset_init(&rdataset); + 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 SIG set, skip it. */ + if (rdataset.type == dns_rdatatype_sig) + goto skip; + + /* + * If this is a KEY set at the apex, look for a signedkey file. + */ + if (atorigin && rdataset.type == dns_rdatatype_key) { + importparentsig(&diff, name, &rdataset); + goto skip; + } + + /* + * If this name is a delegation point, skip all records + * except an NXT set a KEY set containing a null key. + */ + if (isdelegation) { + if (!(rdataset.type == dns_rdatatype_nxt || + (rdataset.type == dns_rdatatype_key && + hasnullkey(&rdataset)))) + goto skip; + } + + if (rdataset.type == dns_rdatatype_nxt) { + if (!nokeys) + nxt_setbit(&rdataset, dns_rdatatype_sig); + if (neednullkey) + nxt_setbit(&rdataset, dns_rdatatype_key); + } + + signset(&diff, node, name, &rdataset); + + skip: + dns_rdataset_disassociate(&rdataset); + result = dns_rdatasetiter_next(rdsiter); + } + if (result != ISC_R_NOMORE) { + char namestr[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namestr, sizeof namestr); + fatal("rdataset iteration for name '%s' failed: %s", + namestr, isc_result_totext(result)); + } + dns_rdatasetiter_destroy(&rdsiter); + + result = dns_diff_apply(&diff, gdb, gversion); + if (result != ISC_R_SUCCESS) { + char namestr[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namestr, sizeof namestr); + fatal("failed to add SIGs at node '%s': %s", + namestr, isc_result_totext(result)); + } + dns_diff_clear(&diff); +} + +static inline isc_boolean_t +active_node(dns_dbnode_t *node) { + dns_rdatasetiter_t *rdsiter; + isc_boolean_t active = ISC_FALSE; + isc_result_t result; + dns_rdataset_t rdataset; + + dns_rdataset_init(&rdataset); + 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 (rdataset.type != dns_rdatatype_nxt) + 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)); + dns_rdatasetiter_destroy(&rdsiter); + + if (!active) { + /* + * Make sure there is no NXT record for this node. + */ + result = dns_db_deleterdataset(gdb, node, gversion, + dns_rdatatype_nxt, 0); + if (result == DNS_R_UNCHANGED) + result = ISC_R_SUCCESS; + check_result(result, "dns_db_deleterdataset"); + } + + return (active); +} + +static inline isc_result_t +next_active(dns_name_t *name, dns_dbnode_t **nodep) { + isc_result_t result; + isc_boolean_t active; + + do { + active = ISC_FALSE; + result = dns_dbiterator_current(gdbiter, nodep, name); + if (result == ISC_R_SUCCESS) { + active = active_node(*nodep); + if (!active) { + dns_db_detachnode(gdb, nodep); + result = dns_dbiterator_next(gdbiter); + } + } + } while (result == ISC_R_SUCCESS && !active); + + return (result); +} + +static inline isc_result_t +next_nonglue(dns_name_t *name, dns_dbnode_t **nodep, dns_name_t *origin, + dns_name_t *lastcut) +{ + isc_result_t result; + + do { + result = next_active(name, nodep); + if (result == ISC_R_SUCCESS) { + if (dns_name_issubdomain(name, origin) && + (lastcut == NULL || + !dns_name_issubdomain(name, lastcut))) + return (ISC_R_SUCCESS); + result = dns_master_dumpnodetostream(mctx, gdb, + gversion, + *nodep, name, + masterstyle, fp); + check_result(result, "dns_master_dumpnodetostream"); + dns_db_detachnode(gdb, nodep); + result = dns_dbiterator_next(gdbiter); + } + } while (result == ISC_R_SUCCESS); + return (result); +} + +/* + * 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_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) { + char namestr[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namestr, sizeof namestr); + fatal("failed to find '%s SOA' in the zone: %s", + namestr, isc_result_totext(result)); + } + ttl = soaset.ttl; + dns_rdataset_disassociate(&soaset); + return (ttl); +} + +/* + * Delete any SIG 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; + + 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_sig) { + 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_sig, + 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()"); + + lastzonecut = NULL; + + zonettl = soattl(); + +} + +/* + * Clean up the iterator and global state after the tasks complete. + */ +static void +postsign(void) { + if (lastzonecut != NULL) { + dns_name_free(lastzonecut, mctx); + isc_mem_put(mctx, lastzonecut, sizeof(dns_name_t)); + } + dns_dbiterator_destroy(&gdbiter); +} + +/* + * Find the next name to nxtify & sign + */ +static isc_result_t +getnextname(dns_name_t *name, dns_name_t *nextname, dns_dbnode_t **nodep) { + isc_result_t result; + dns_dbnode_t *nextnode, *curnode; + + LOCK(&namelock); + + if (shuttingdown || finished) { + result = ISC_R_NOMORE; + if (gnode != NULL) + dns_db_detachnode(gdb, &gnode); + goto out; + } + + if (gnode == NULL) { + dns_fixedname_t ftname; + dns_name_t *tname; + + dns_fixedname_init(&ftname); + tname = dns_fixedname_name(&ftname); + + result = next_nonglue(tname, &gnode, gorigin, lastzonecut); + if (result != ISC_R_SUCCESS) + fatal("failed to iterate through the zone"); + } + + nextnode = NULL; + curnode = NULL; + dns_dbiterator_current(gdbiter, &curnode, name); + if (!dns_name_equal(name, gorigin)) { + dns_rdatasetiter_t *rdsiter = NULL; + dns_rdataset_t set; + + dns_rdataset_init(&set); + result = dns_db_allrdatasets(gdb, curnode, gversion, 0, + &rdsiter); + check_result(result, "dns_db_allrdatasets"); + result = dns_rdatasetiter_first(rdsiter); + while (result == ISC_R_SUCCESS) { + dns_rdatasetiter_current(rdsiter, &set); + if (set.type == dns_rdatatype_ns) { + dns_rdataset_disassociate(&set); + break; + } + dns_rdataset_disassociate(&set); + result = dns_rdatasetiter_next(rdsiter); + } + if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) + fatal("rdataset iteration failed: %s", + isc_result_totext(result)); + if (result == ISC_R_SUCCESS) { + if (lastzonecut != NULL) + dns_name_free(lastzonecut, mctx); + else { + lastzonecut = isc_mem_get(mctx, + sizeof(dns_name_t)); + if (lastzonecut == NULL) + fatal("out of memory"); + } + dns_name_init(lastzonecut, NULL); + result = dns_name_dup(name, mctx, lastzonecut); + check_result(result, "dns_name_dup()"); + } + dns_rdatasetiter_destroy(&rdsiter); + } + result = dns_dbiterator_next(gdbiter); + if (result == ISC_R_SUCCESS) + result = next_nonglue(nextname, &nextnode, gorigin, + lastzonecut); + if (result == ISC_R_NOMORE) { + dns_name_clone(gorigin, nextname); + finished = ISC_TRUE; + result = ISC_R_SUCCESS; + } else if (result != ISC_R_SUCCESS) + fatal("iterating through the database failed: %s", + isc_result_totext(result)); + dns_db_detachnode(gdb, &curnode); + + *nodep = gnode; + gnode = nextnode; + + out: + UNLOCK(&namelock); + return (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, *fnextname; + dns_dbnode_t *node; + sevent_t *sevent; + isc_result_t result; + + fname = isc_mem_get(mctx, sizeof(dns_fixedname_t)); + fnextname = isc_mem_get(mctx, sizeof(dns_fixedname_t)); + if (fname == NULL || fnextname == NULL) + fatal("out of memory"); + dns_fixedname_init(fname); + dns_fixedname_init(fnextname); + node = NULL; + result = getnextname(dns_fixedname_name(fname), + dns_fixedname_name(fnextname), &node); + if (result == ISC_R_NOMORE) { + isc_mem_put(mctx, fname, sizeof(dns_fixedname_t)); + isc_mem_put(mctx, fnextname, sizeof(dns_fixedname_t)); + if (assigned == completed) { + isc_task_detach(&task); + isc_app_shutdown(); + } + return; + } + 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; + sevent->fnextname = fnextname; + isc_task_send(worker, ISC_EVENT_PTR(&sevent)); + assigned++; +} + +/* + * 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_result_t result; + isc_task_t *worker; + sevent_t *sevent = (sevent_t *)event; + + completed++; + worker = (isc_task_t *)event->ev_sender; + result = dns_master_dumpnodetostream(mctx, gdb, gversion, + sevent->node, + dns_fixedname_name(sevent->fname), + masterstyle, fp); + check_result(result, "dns_master_dumpnodetostream"); + 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 and nxtify a database node. + */ +static void +sign(isc_task_t *task, isc_event_t *event) { + dns_fixedname_t *fname, *fnextname; + dns_dbnode_t *node; + sevent_t *sevent, *wevent; + isc_result_t result; + + sevent = (sevent_t *)event; + node = sevent->node; + fname = sevent->fname; + fnextname = sevent->fnextname; + isc_event_free(&event); + + result = dns_nxt_build(gdb, gversion, node, + dns_fixedname_name(fnextname), zonettl); + check_result(result, "dns_nxt_build()"); + isc_mem_put(mctx, fnextname, sizeof(dns_fixedname_t)); + 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)); +} + +/* + * 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_load(*db, file); + 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], ISC_FALSE); + 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_key, 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 +print_time(FILE *fp) { + time_t currenttime; + + currenttime = time(NULL); + fprintf(fp, "; File written on %s", ctime(¤ttime)); +} + +static void +print_version(FILE *fp) { + 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, "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 signedkey files (.)\n"); + fprintf(stderr, "\t-s YYYYMMDDHHMMSS|+offset:\n"); + fprintf(stderr, "\t\tSIG start time - absolute|offset (now)\n"); + fprintf(stderr, "\t-e YYYYMMDDHHMMSS|+offset|\"now\"+offset]:\n"); + fprintf(stderr, "\t\tSIG 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-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-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, "\n"); + + fprintf(stderr, "Signing Keys: "); + fprintf(stderr, "(default: all zone keys that have private keys)\n"); + fprintf(stderr, "\tkeyfile (Kname+alg+tag)\n"); +#ifndef ISC_RFC2535 + fprintf(stderr, +"WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING\n" +"WARNING WARNING\n" +"WARNING This version of dnssec-signzone produces zones that are WARNING\n" +"WARNING incompatible with the forthcoming DS based DNSSEC WARNING\n" +"WARNING standard. WARNING\n" +"WARNING WARNING\n" +"WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING\n"); +#endif + exit(0); +} + +static void +removetempfile(void) { + if (removefile) + isc_file_remove(tempfile); +} + +int +main(int argc, char *argv[]) { + int i, ch; + char *startstr = NULL, *endstr = NULL, *classname = NULL; + char *origin = NULL, *file = NULL, *output = NULL; + char *randomfile = NULL; + 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_textregion_t r; + isc_task_t **tasks = NULL; + 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(); + + while ((ch = isc_commandline_parse(argc, argv, + "c:s:e:i:v:o:f:ahpr:td:n:")) + != -1) { + switch (ch) { + case 'c': + classname = isc_commandline_argument; + break; + + case 's': + startstr = isc_commandline_argument; + break; + + case 'e': + endstr = isc_commandline_argument; + break; + + 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 'p': + pseudorandom = ISC_TRUE; + break; + + case 'r': + randomfile = isc_commandline_argument; + break; + + case 'v': + endp = NULL; + verbose = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') + fatal("verbose level must be numeric"); + break; + + case 'o': + origin = isc_commandline_argument; + break; + + case 'f': + output = isc_commandline_argument; + break; + + case 'a': + tryverify = ISC_TRUE; + break; + + case 't': + printstats = ISC_TRUE; + break; + + case 'd': + directory = 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 'h': + default: + usage(); + + } + } + +#ifndef ISC_RFC2535 + fprintf(stderr, +"WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING\n" +"WARNING WARNING\n" +"WARNING This version of dnssec-signzone produces zones that are WARNING\n" +"WARNING incompatible with the forth coming DS based DNSSEC WARNING\n" +"WARNING standard. WARNING\n" +"WARNING WARNING\n" +"WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING\n"); +#endif + + setup_entropy(mctx, randomfile, &ectx); + eflags = ISC_ENTROPY_BLOCKING; + if (!pseudorandom) + eflags |= ISC_ENTROPY_GOODONLY; + 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; + + 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); + + + if (classname != NULL) { + r.base = classname; + r.length = strlen(classname); + result = dns_rdataclass_fromtext(&rdclass, &r); + if (result != ISC_R_SUCCESS) + fatal("unknown class %s",classname); + } else + rdclass = dns_rdataclass_in; + + 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 (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 (origin == NULL) + origin = file; + + gdb = NULL; + isc_time_now(&timer_start); + loadzone(file, origin, rdclass, &gdb); + gorigin = dns_db_origin(gdb); + + ISC_LIST_INIT(keylist); + + if (argc == 0) { + signer_key_t *key; + + loadzonekeys(gdb); + + key = ISC_LIST_HEAD(keylist); + while (key != NULL) { + key->isdefault = ISC_TRUE; + key = ISC_LIST_NEXT(key, link); + } + } 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 key %s: %s", argv[i], + isc_result_totext(result)); + + 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))) + { + key->isdefault = ISC_TRUE; + if (!dst_key_isprivate(dkey)) + fatal("cannot sign zone with " + "non-private key %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); + } + + if (ISC_LIST_EMPTY(keylist)) { + fprintf(stderr, "%s: warning: No keys specified or found\n", + program); + nokeys = ISC_TRUE; + } + + gversion = NULL; + result = dns_db_newversion(gdb, &gversion); + check_result(result, "dns_db_newversion()"); + + 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)); + result = isc_app_onrun(mctx, master, startworker, tasks[i]); + if (result != ISC_R_SUCCESS) + fatal("failed to start 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(); + (void)isc_app_run(); + if (!finished) + fatal("process aborted by user"); + 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(); + + 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); + + cleanup_logging(&log); + dst_lib_destroy(); + cleanup_entropy(&ectx); + if (verbose > 10) + isc_mem_stats(mctx, stdout); + isc_mem_destroy(&mctx); + + (void) isc_app_finish(); + + if (printstats) { + isc_uint64_t runtime_us; /* Runtime in microseconds */ + isc_uint64_t runtime_ms; /* Runtime in milliseconds */ + isc_uint64_t sig_ms; /* Signatures per millisecond */ + + isc_time_now(&timer_finish); + + 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); + } + } + + return (0); +} diff --git a/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signzone.html b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signzone.html new file mode 100644 index 0000000000..a4f5024573 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dnssec/dnssec-signzone.html @@ -0,0 +1,556 @@ + + + + +dnssec-signzone

dnssec-signzone

Name

dnssec-signzone -- DNSSEC zone signing tool

Synopsis

dnssec-signzone [-a] [-c class] [-d directory] [-s start-time] [-e end-time] [-f output-file] [-h] [-i interval] [-n nthreads] [-o origin] [-p] [-r randomdev] [-t] [-v level] {zonefile} [key...]

DESCRIPTION

dnssec-signzone signs a zone. It generates NXT + and SIG records and produces a signed version of the zone. If there + is a signedkey file from the zone's parent, + the parent's signatures will be incorporated into the generated + signed zone file. 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 + signedkey file for each child zone. +

OPTIONS

-a

Verify all generated signatures. +

-c class

Specifies the DNS class of the zone. +

-d directory

Look for signedkey files in + directory as the directory +

-s start-time

Specify the date and time when the generated SIG 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 is used. +

-e end-time

Specify the date and time when the generated SIG 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 file. +

-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 SIG 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 SIG records + are due to expire in less than 7.5 days, they would be + replaced. +

-n ncpus

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

-o origin

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

-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. +

zonefile

The file containing the zone to be signed. + Sets the debugging level. +

key

The keys used to sign the zone. If no keys are specified, the + default all zone keys that have private key files in the + current directory. +

EXAMPLE

The following command signs the example.com + zone with the DSA key generated in the dnssec-keygen + man page. The zone's keys must be in the zone. If there are + signedkey files associated with this zone + or any child zones, they must be in the current directory. + example.com, the following command would be + issued: +

dnssec-signzone -o example.com db.example.com Kexample.com.+003+26160 +

The command would print a string of the form: +

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

SEE ALSO

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

AUTHOR

Internet Systems Consortium +

diff --git a/contrib/bind-9.2.4rc7/bin/dnssec/dnssectool.c b/contrib/bind-9.2.4rc7/bin/dnssec/dnssectool.c new file mode 100644 index 0000000000..4142bd7a58 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dnssec/dnssectool.c @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001, 2003 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: dnssectool.c,v 1.31.2.5 2004/03/09 06:09:16 marka Exp $ */ + +#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; + +static isc_entropysource_t *source = NULL; +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_sig_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; + + 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; + 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"); + } + + 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)); +} + +void +cleanup_entropy(isc_entropy_t **ectx) { + if (source != NULL) + isc_entropy_destroysource(&source); + isc_entropy_detach(ectx); +} + +isc_stdtime_t +strtotime(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); +} diff --git a/contrib/bind-9.2.4rc7/bin/dnssec/dnssectool.h b/contrib/bind-9.2.4rc7/bin/dnssec/dnssectool.h new file mode 100644 index 0000000000..1d760d4817 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/dnssec/dnssectool.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 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: dnssectool.h,v 1.15.2.1 2004/03/09 06:09:16 marka 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_sig_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(char *str, isc_int64_t now, isc_int64_t base); + +#endif /* DNSSEC_DNSSECTOOL_H */ diff --git a/contrib/bind-9.2.4rc7/bin/named/aclconf.c b/contrib/bind-9.2.4rc7/bin/named/aclconf.c new file mode 100644 index 0000000000..d9f17f1baa --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/aclconf.c @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 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: aclconf.c,v 1.27.2.1 2004/03/09 06:09:17 marka Exp $ */ + +#include + +#include +#include /* Required for HP/UX (and others?) */ +#include + +#include +#include +#include + +#include + +void +ns_aclconfctx_init(ns_aclconfctx_t *ctx) { + ISC_LIST_INIT(ctx->named_acl_cache); +} + +void +ns_aclconfctx_destroy(ns_aclconfctx_t *ctx) { + dns_acl_t *dacl, *next; + for (dacl = ISC_LIST_HEAD(ctx->named_acl_cache); + dacl != NULL; + dacl = next) + { + next = ISC_LIST_NEXT(dacl, nextincache); + dns_acl_detach(&dacl); + } +} + +/* + * Find the definition of the named acl whose name is "name". + */ +static isc_result_t +get_acl_def(cfg_obj_t *cctx, char *name, cfg_obj_t **ret) { + isc_result_t result; + cfg_obj_t *acls = NULL; + cfg_listelt_t *elt; + + result = cfg_map_get(cctx, "acl", &acls); + if (result != ISC_R_SUCCESS) + return (result); + for (elt = cfg_list_first(acls); + elt != NULL; + elt = cfg_list_next(elt)) { + cfg_obj_t *acl = cfg_listelt_value(elt); + const char *aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name")); + if (strcasecmp(aclname, name) == 0) { + *ret = cfg_tuple_get(acl, "value"); + return (ISC_R_SUCCESS); + } + } + return (ISC_R_NOTFOUND); +} + +static isc_result_t +convert_named_acl(cfg_obj_t *nameobj, cfg_obj_t *cctx, + ns_aclconfctx_t *ctx, isc_mem_t *mctx, + dns_acl_t **target) +{ + isc_result_t result; + cfg_obj_t *cacl = NULL; + dns_acl_t *dacl; + char *aclname = cfg_obj_asstring(nameobj); + + /* Look for an already-converted version. */ + for (dacl = ISC_LIST_HEAD(ctx->named_acl_cache); + dacl != NULL; + dacl = ISC_LIST_NEXT(dacl, nextincache)) + { + if (strcasecmp(aclname, dacl->name) == 0) { + dns_acl_attach(dacl, target); + return (ISC_R_SUCCESS); + } + } + /* Not yet converted. Convert now. */ + result = get_acl_def(cctx, aclname, &cacl); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(nameobj, dns_lctx, ISC_LOG_WARNING, + "undefined ACL '%s'", aclname); + return (result); + } + result = ns_acl_fromconfig(cacl, cctx, ctx, mctx, &dacl); + if (result != ISC_R_SUCCESS) + return (result); + dacl->name = isc_mem_strdup(dacl->mctx, aclname); + if (dacl->name == NULL) + return (ISC_R_NOMEMORY); + ISC_LIST_APPEND(ctx->named_acl_cache, dacl, nextincache); + dns_acl_attach(dacl, target); + return (ISC_R_SUCCESS); +} + +static isc_result_t +convert_keyname(cfg_obj_t *keyobj, isc_mem_t *mctx, dns_name_t *dnsname) { + isc_result_t result; + isc_buffer_t buf; + dns_fixedname_t fixname; + unsigned int keylen; + const char *txtname = cfg_obj_asstring(keyobj); + + keylen = strlen(txtname); + isc_buffer_init(&buf, txtname, keylen); + isc_buffer_add(&buf, keylen); + dns_fixedname_init(&fixname); + result = dns_name_fromtext(dns_fixedname_name(&fixname), &buf, + dns_rootname, ISC_FALSE, NULL); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(keyobj, dns_lctx, ISC_LOG_WARNING, + "key name '%s' is not a valid domain name", + txtname); + return (result); + } + return (dns_name_dup(dns_fixedname_name(&fixname), mctx, dnsname)); +} + +isc_result_t +ns_acl_fromconfig(cfg_obj_t *caml, + cfg_obj_t *cctx, + ns_aclconfctx_t *ctx, + isc_mem_t *mctx, + dns_acl_t **target) +{ + isc_result_t result; + unsigned int count; + dns_acl_t *dacl = NULL; + dns_aclelement_t *de; + cfg_listelt_t *elt; + + REQUIRE(target != NULL && *target == NULL); + + count = 0; + for (elt = cfg_list_first(caml); + elt != NULL; + elt = cfg_list_next(elt)) + count++; + + result = dns_acl_create(mctx, count, &dacl); + if (result != ISC_R_SUCCESS) + return (result); + + de = dacl->elements; + for (elt = cfg_list_first(caml); + elt != NULL; + elt = cfg_list_next(elt)) + { + cfg_obj_t *ce = cfg_listelt_value(elt); + if (cfg_obj_istuple(ce)) { + /* This must be a negated element. */ + ce = cfg_tuple_get(ce, "value"); + de->negative = ISC_TRUE; + } else { + de->negative = ISC_FALSE; + } + + if (cfg_obj_isnetprefix(ce)) { + /* Network prefix */ + de->type = dns_aclelementtype_ipprefix; + + cfg_obj_asnetprefix(ce, + &de->u.ip_prefix.address, + &de->u.ip_prefix.prefixlen); + } else if (cfg_obj_istype(ce, &cfg_type_keyref)) { + /* Key name */ + de->type = dns_aclelementtype_keyname; + dns_name_init(&de->u.keyname, NULL); + result = convert_keyname(ce, mctx, &de->u.keyname); + if (result != ISC_R_SUCCESS) + goto cleanup; + } else if (cfg_obj_islist(ce)) { + /* Nested ACL */ + de->type = dns_aclelementtype_nestedacl; + result = ns_acl_fromconfig(ce, cctx, ctx, mctx, + &de->u.nestedacl); + if (result != ISC_R_SUCCESS) + goto cleanup; + } else if (cfg_obj_isstring(ce)) { + /* ACL name */ + char *name = cfg_obj_asstring(ce); + if (strcasecmp(name, "localhost") == 0) { + de->type = dns_aclelementtype_localhost; + } else if (strcasecmp(name, "localnets") == 0) { + de->type = dns_aclelementtype_localnets; + } else if (strcasecmp(name, "any") == 0) { + de->type = dns_aclelementtype_any; + } else if (strcasecmp(name, "none") == 0) { + de->type = dns_aclelementtype_any; + de->negative = ISC_TF(! de->negative); + } else { + de->type = dns_aclelementtype_nestedacl; + result = convert_named_acl(ce, cctx, ctx, mctx, + &de->u.nestedacl); + if (result != ISC_R_SUCCESS) + goto cleanup; + } + } else { + cfg_obj_log(ce, dns_lctx, ISC_LOG_WARNING, + "address match list contains " + "unsupported element type"); + result = ISC_R_FAILURE; + goto cleanup; + } + de++; + dacl->length++; + } + + *target = dacl; + return (ISC_R_SUCCESS); + + cleanup: + dns_acl_detach(&dacl); + return (result); +} diff --git a/contrib/bind-9.2.4rc7/bin/named/client.c b/contrib/bind-9.2.4rc7/bin/named/client.c new file mode 100644 index 0000000000..4074fbd0e3 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/client.c @@ -0,0 +1,2215 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2003 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: client.c,v 1.176.2.16 2004/07/23 02:56:59 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 + +/*** + *** Client + ***/ + +/* + * 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 + +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 inactive; /* To be recycled */ +}; + +#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. + */ + + +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_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. + */ + 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)) + 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_put(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; + 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) + 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]; + + REQUIRE(NS_CLIENT_VALID(client)); + + CTRACE("send"); + + if ((client->attributes & NS_CLIENTATTR_RA) != 0) + client->message->flags |= DNS_MESSAGEFLAG_RA; + + /* + * 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); + /* + * XXXRTH dns_message_setopt() should probably do this... + */ + 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); + 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); + 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, 0); + 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); + 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); +} + +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); + + /* + * 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; + + 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. + */ + rdatalist->rdclass = RECV_BUFFER_SIZE; + + /* + * Set EXTENDED-RCODE, VERSION, and Z to 0. + */ +#ifdef ISC_RFC2535 + rdatalist->ttl = (client->extflags & DNS_MESSAGEEXTFLAG_REPLYPRESERVE); +#else + rdatalist->ttl = 0; +#endif + + /* + * No ENDS options in the default case. + */ + 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); + dns_rdatalist_tordataset(rdatalist, rdataset); + + client->opt = rdataset; + + return (ISC_R_SUCCESS); +} + +static inline isc_boolean_t +allowed(isc_netaddr_t *addr, dns_acl_t *acl) { + int match; + isc_result_t result; + + if (acl == NULL) + return (ISC_TRUE); + result = dns_acl_match(addr, NULL, acl, &ns_g_server->aclenv, + &match, NULL); + if (result == ISC_R_SUCCESS && match > 0) + return (ISC_TRUE); + return (ISC_FALSE); +} + +/* + * 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_buffer_t *buffer; + isc_buffer_t tbuffer; + dns_view_t *view; + dns_rdataset_t *opt; + 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; + + REQUIRE(event != NULL); + client = event->ev_arg; + REQUIRE(NS_CLIENT_VALID(client)); + REQUIRE(task == client->task); + + UNUSED(task); + + INSIST(client->recursionquota == NULL); + + INSIST(client->state == + TCP_CLIENT(client) ? + NS_CLIENTSTATE_READING : + NS_CLIENTSTATE_READY); + + 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_stdtime_get(&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); + + 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; + } + } + + if ((client->attributes & NS_CLIENTATTR_MULTICAST) != 0) { + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2), + "multicast request"); +#if 0 + ns_client_error(client, DNS_R_REFUSED); +#endif + } + + 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; + } + } + + /* + * 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; + } + + 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; + + /* + * Deal with EDNS. + */ + opt = dns_message_getopt(client->message); + if (opt != NULL) { + unsigned int version; + + /* + * 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); + + /* + * Create an OPT for our reply. + */ + result = client_addopt(client); + if (result != ISC_R_SUCCESS) { + ns_client_error(client, result); + goto cleanup; + } + + /* + * Do we understand this version of ENDS? + * + * XXXRTH need library support for this! + */ + version = (opt->ttl & 0x00FF0000) >> 16; + if (version != 0) { + ns_client_error(client, DNS_R_BADVERS); + 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. For TCP/IPv6, we get this from + * the receiving socket. For UDP/IPv6, we get it from the pktinfo + * structure (if supported). For IPv4, we have to do with + * the address of the interface where the request was received. + */ + if (client->interface->addr.type.sa.sa_family == AF_INET6) { + 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->attributes & NS_CLIENTATTR_PKTINFO) != 0) { + isc_netaddr_fromin6(&destaddr, &client->pktinfo.ipi6_addr); + result = ISC_R_SUCCESS; + } + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "failed to get request's " + "destination: %s", + isc_result_totext(result)); + goto cleanup; + } + } else { + isc_netaddr_fromsockaddr(&destaddr, &client->interface->addr); + } + + /* + * 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) + { + if (allowed(&netaddr, view->matchclients) && + allowed(&destaddr, view->matchdestinations) && + !((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; + 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. + */ + sigresult = dns_message_checksig(client->message, client->view); + client->signer = NULL; + dns_name_init(&client->signername, NULL); + result = dns_message_signer(client->message, &client->signername); + 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 { + /* There is a signature, but it is bad. */ + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, ISC_LOG_ERROR, + "request has invalid signature: %s", + isc_result_totext(result)); + /* + * 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. + */ + ra = ISC_FALSE; + if (client->view->resolver != NULL && + client->view->recursion == ISC_TRUE && + /* XXX this will log too much too early */ + ns_client_checkacl(client, "recursion available:", + client->view->recursionacl, + ISC_TRUE, ISC_LOG_DEBUG(1)) == ISC_R_SUCCESS) + ra = ISC_TRUE; + + if (ra == ISC_TRUE) + client->attributes |= NS_CLIENTATTR_RA; + + /* + * 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 +client_create(ns_clientmgr_t *manager, ns_client_t **clientp) +{ + ns_client_t *client; + isc_result_t result; + + /* + * 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); + + client = isc_mem_get(manager->mctx, sizeof *client); + if (client == NULL) + return (ISC_R_NOMEMORY); + + 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(manager->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(manager->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(manager->mctx, RECV_BUFFER_SIZE); + if (client->recvbuf == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup_sendevent; + } + + client->recvevent = (isc_socketevent_t *) + isc_event_allocate(manager->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->mctx = manager->mctx; + 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->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(manager->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_put(manager->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; + 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 legititmate 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_recv() failed: %s", + isc_result_totext(result)); + /* + * This cannot happen in the current implementation, since + * isc_socket_recv2() cannot fail if flags == 0A + * + * 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) { + REQUIRE(ISC_LIST_EMPTY(manager->active)); + REQUIRE(ISC_LIST_EMPTY(manager->inactive)); + + MTRACE("clientmgr_destroy"); + + 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; + + 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); + 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->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)) + 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, 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; + } + + isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); + + 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, + const char *opname, dns_acl_t *acl, + isc_boolean_t default_allow, int log_level) +{ + isc_result_t result = + ns_client_checkaclsilent(client, 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); +} + +static 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); + +static 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]; + + vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); + ns_client_name(client, peerbuf, sizeof peerbuf); + + isc_log_write(ns_g_lctx, category, module, level, + "client %s: %s", peerbuf, 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_rdataclass_t rdclass, + char *buf, size_t len) +{ + char namebuf[DNS_NAME_FORMATSIZE]; + char classbuf[DNS_RDATACLASS_FORMATSIZE]; + + dns_name_format(name, namebuf, sizeof(namebuf)); + dns_rdataclass_format(rdclass, classbuf, sizeof(classbuf)); + (void)snprintf(buf, len, "%s '%s/%s'", msg, namebuf, 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); +} diff --git a/contrib/bind-9.2.4rc7/bin/named/config.c b/contrib/bind-9.2.4rc7/bin/named/config.c new file mode 100644 index 0000000000..fc650ec67c --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/config.c @@ -0,0 +1,455 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001, 2002 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: config.c,v 1.11.2.6 2004/04/19 23:15:38 marka Exp $ */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include + +static char defaultconf[] = "\ +options {\n\ +# blackhole {none;};\n" +#ifndef WIN32 +" coresize default;\n\ + datasize default;\n\ + files default;\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\ +" +#ifdef PATH_RANDOMDEV +"\ + random-device \"" PATH_RANDOMDEV "\";\n\ +" +#endif +"\ + recursive-clients 1000;\n\ + rrset-order {order cyclic;};\n\ + serial-queries 20;\n\ + serial-query-rate 20;\n\ + statistics-file \"named.stats\";\n\ + statistics-interval 60;\n\ + tcp-clients 100;\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\ + version \""VERSION"\";\n\ +\n\ + /* view */\n\ + allow-notify {none;};\n\ + allow-update-forwarding {none;};\n\ + allow-recursion {any;};\n\ + allow-v6-synthesis {none;};\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 60;\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 ignore;\n\ + check-names slave ignore;\n\ + check-names response ignore;\n\ +\n\ + /* zone */\n\ + allow-query {any;};\n\ + allow-transfer {any;};\n\ + notify yes;\n\ +# also-notify \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\ + 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\ + sig-validity-interval 30; /* days */\n\ + zone-statistics false;\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(cfg_obj_t **maps, const char* name, 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); + } +} + +int +ns_config_listcount(cfg_obj_t *list) { + 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(cfg_obj_t *classobj, dns_rdataclass_t defclass, + dns_rdataclass_t *classp) { + char *str; + isc_textregion_t r; + isc_result_t result; + + if (!cfg_obj_isstring(classobj)) { + *classp = defclass; + return (ISC_R_SUCCESS); + } + str = cfg_obj_asstring(classobj); + r.base = str; + r.length = strlen(str); + result = dns_rdataclass_fromtext(classp, &r); + if (result != ISC_R_SUCCESS) + cfg_obj_log(classobj, ns_g_lctx, ISC_LOG_ERROR, + "unknown class '%s'", str); + return (result); +} + +dns_zonetype_t +ns_config_getzonetype(cfg_obj_t *zonetypeobj) { + dns_zonetype_t ztype = dns_zone_none; + 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(cfg_obj_t *config, cfg_obj_t *list, + in_port_t defport, isc_mem_t *mctx, + isc_sockaddr_t **addrsp, isc_uint32_t *countp) +{ + int count, i = 0; + cfg_obj_t *addrlist; + cfg_obj_t *portobj; + cfg_listelt_t *element; + isc_sockaddr_t *addrs; + in_port_t port; + isc_result_t result; + + INSIST(addrsp != NULL && *addrsp == 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; +} + +isc_result_t +ns_config_getipandkeylist(cfg_obj_t *config, cfg_obj_t *list, isc_mem_t *mctx, + isc_sockaddr_t **addrsp, dns_name_t ***keysp, + isc_uint32_t *countp) +{ + isc_uint32_t count, i = 0; + isc_result_t result; + cfg_listelt_t *element; + cfg_obj_t *addrlist; + cfg_obj_t *portobj; + in_port_t port; + dns_fixedname_t fname; + isc_sockaddr_t *addrs = NULL; + dns_name_t **keys = NULL; + + INSIST(addrsp != NULL && *addrsp == 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 { + result = ns_config_getport(config, &port); + if (result != ISC_R_SUCCESS) + return (result); + } + + result = ISC_R_NOMEMORY; + + addrs = isc_mem_get(mctx, count * sizeof(isc_sockaddr_t)); + if (addrs == NULL) + goto cleanup; + + keys = isc_mem_get(mctx, count * sizeof(dns_name_t *)); + if (keys == NULL) + goto cleanup; + + for (element = cfg_list_first(addrlist); + element != NULL; + element = cfg_list_next(element), i++) + { + cfg_obj_t *addr; + cfg_obj_t *key; + char *keystr; + isc_buffer_t b; + + INSIST(i < count); + + addr = cfg_tuple_get(cfg_listelt_value(element), "sockaddr"); + key = cfg_tuple_get(cfg_listelt_value(element), "key"); + + 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)) + 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; + } + INSIST(i == count); + + *addrsp = addrs; + *keysp = keys; + *countp = count; + + return (ISC_R_SUCCESS); + + cleanup: + if (addrs != NULL) + isc_mem_put(mctx, addrs, count * sizeof(isc_sockaddr_t)); + if (keys != NULL) { + unsigned int j; + 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, count * sizeof(dns_name_t *)); + } + 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(cfg_obj_t *config, in_port_t *portp) { + cfg_obj_t *maps[3]; + cfg_obj_t *options = NULL; + cfg_obj_t *portobj = NULL; + isc_result_t result; + int i; + + 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); +} + +isc_result_t +ns_config_getkeyalgorithm(const char *str, dns_name_t **name) +{ + if (strcasecmp(str, "hmac-md5") == 0 || + strcasecmp(str, "hmac-md5.sig-alg.reg.int") == 0 || + strcasecmp(str, "hmac-md5.sig-alg.reg.int.") == 0) + { + if (name != NULL) + *name = dns_tsig_hmacmd5_name; + return (ISC_R_SUCCESS); + } + return (ISC_R_NOTFOUND); +} diff --git a/contrib/bind-9.2.4rc7/bin/named/control.c b/contrib/bind-9.2.4rc7/bin/named/control.c new file mode 100644 index 0000000000..a50aa921cb --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/control.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001, 2003 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: control.c,v 1.7.2.4 2004/04/06 01:38:47 marka Exp $ */ + +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include + +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; + + 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); + } + + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_CONTROL, ISC_LOG_DEBUG(1), + "received control channel command '%s'", + command); + + /* + * Compare the 'command' parameter against all known control commands. + */ + if (command_compare(command, NS_COMMAND_RELOAD)) { + result = ns_server_reloadcommand(ns_g_server, command); + } 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); + } else if (command_compare(command, NS_COMMAND_HALT)) { + ns_server_flushonshutdown(ns_g_server, ISC_FALSE); + isc_app_shutdown(); + result = ISC_R_SUCCESS; + } else if (command_compare(command, NS_COMMAND_STOP)) { + ns_server_flushonshutdown(ns_g_server, ISC_TRUE); + 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); + 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_STATUS)) { + result = ns_server_status(ns_g_server, text); + } else if (command_compare(command, NS_COMMAND_NULL)) { + result = ISC_R_SUCCESS; + } 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.2.4rc7/bin/named/controlconf.c b/contrib/bind-9.2.4rc7/bin/named/controlconf.c new file mode 100644 index 0000000000..04f344a34b --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/controlconf.c @@ -0,0 +1,1329 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001, 2003 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: controlconf.c,v 1.28.2.10 2004/03/09 06:09:18 marka Exp $ */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#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_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); + 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; + else 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); + isc_mem_put(listener->mctx, secret.rstart, + REGION_SIZE(secret)); + } 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; + } + + 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; + } + + 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; + } + } else { + log_invalid(&conn->ccmsg, ISC_R_FAILURE); + goto cleanup; + } + + /* + * 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; + } + + /* + * 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; + } + + 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; + } + + /* + * 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; + 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; + } + } + + 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; + } + } + + _ctrl = isccc_alist_lookup(response, "_ctrl"); + if (_ctrl == NULL || + isccc_cc_defineuint32(_ctrl, "_nonce", conn->nonce) == NULL) + goto cleanup; + + 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; + 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; + conn->sending = ISC_TRUE; + + if (secret.rstart != NULL) + isc_mem_put(listener->mctx, secret.rstart, + REGION_SIZE(secret)); + if (request != NULL) + isccc_sexpr_free(&request); + if (response != NULL) + isccc_sexpr_free(&response); + return; + + cleanup: + if (secret.rstart != NULL) + isc_mem_put(listener->mctx, secret.rstart, + REGION_SIZE(secret)); + isc_socket_detach(&conn->sock); + isccc_ccmsg_invalidate(&conn->ccmsg); + conn->ccmsg_valid = ISC_FALSE; + maybe_free_connection(conn); + maybe_free_listener(listener); + if (request != NULL) + isccc_sexpr_free(&request); + if (response != NULL) + isccc_sexpr_free(&response); +} + +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; + (void)isc_socket_getpeername(sock, &peeraddr); + if (!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(cfg_obj_t *keylist, const char *keyname, cfg_obj_t **objp) { + cfg_listelt_t *element; + const char *str; + 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(cfg_obj_t *keylist, isc_mem_t *mctx, + controlkeylist_t *keyids) +{ + cfg_listelt_t *element; + char *newstr = NULL; + const char *str; + cfg_obj_t *obj; + controlkey_t *key = NULL; + + 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); + key = NULL; + newstr = NULL; + } + return (ISC_R_SUCCESS); + + cleanup: + if (newstr != NULL) + isc_mem_free(mctx, newstr); + if (key != NULL) + isc_mem_put(mctx, key, sizeof(*key)); + free_controlkeylist(keyids, mctx); + return (ISC_R_NOMEMORY); +} + +static void +register_keys(cfg_obj_t *control, cfg_obj_t *keylist, + controlkeylist_t *keyids, isc_mem_t *mctx, const char *socktext) +{ + controlkey_t *keyid, *next; + 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 { + cfg_obj_t *algobj = NULL; + cfg_obj_t *secretobj = NULL; + char *algstr = NULL; + 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) != + 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; + cfg_obj_t *key = NULL; + cfg_obj_t *algobj = NULL; + cfg_obj_t *secretobj = NULL; + char *algstr = NULL; + 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(cfg_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) != 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(cfg_obj_t *config, cfg_obj_t *control, + cfg_obj_t **global_keylistp, cfg_obj_t **control_keylistp) +{ + isc_result_t result; + cfg_obj_t *control_keylist = NULL; + 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, cfg_obj_t *control, + cfg_obj_t *config, isc_sockaddr_t *addr, + ns_aclconfctx_t *aclconfctx, const char *socktext) +{ + controllistener_t *listener; + cfg_obj_t *allow; + cfg_obj_t *global_keylist = NULL; + 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. + */ + 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)); + + + /* + * Now, keep the old access list unless a new one can be made. + */ + if (control != NULL) { + allow = cfg_tuple_get(control, "allow"); + result = ns_acl_fromconfig(allow, config, aclconfctx, + listener->mctx, &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); + } else + /* XXXDCL say the old acl is still used? */ + 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)); + + *listenerp = listener; +} + +static void +add_listener(ns_controls_t *cp, controllistener_t **listenerp, + cfg_obj_t *control, cfg_obj_t *config, isc_sockaddr_t *addr, + ns_aclconfctx_t *aclconfctx, const char *socktext) +{ + isc_mem_t *mctx = cp->server->mctx; + controllistener_t *listener; + cfg_obj_t *allow; + cfg_obj_t *global_keylist = NULL; + 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; + ISC_LINK_INIT(listener, link); + ISC_LIST_INIT(listener->keys); + ISC_LIST_INIT(listener->connections); + + /* + * Make the acl. + */ + if (control != NULL) { + allow = cfg_tuple_get(control, "allow"); + result = ns_acl_fromconfig(allow, config, aclconfctx, + mctx, &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) || + (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS)) + result = ISC_R_FAMILYNOSUPPORT; + } + + if (result == ISC_R_SUCCESS) + result = isc_socket_create(ns_g_socketmgr, + isc_sockaddr_pf(&listener->address), + isc_sockettype_tcp, + &listener->sock); + + if (result == ISC_R_SUCCESS) + result = isc_socket_bind(listener->sock, + &listener->address); + + 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, cfg_obj_t *config, + ns_aclconfctx_t *aclconfctx) +{ + controllistener_t *listener; + controllistenerlist_t new_listeners; + cfg_obj_t *controlslist = NULL; + 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)) { + cfg_obj_t *controls; + 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)) { + cfg_obj_t *control; + 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. + * + * "unix" phrases have been reported as + * unsupported by the parser. + */ + 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); + + 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); + + 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); + + 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); + + 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.2.4rc7/bin/named/include/named/aclconf.h b/contrib/bind-9.2.4rc7/bin/named/include/named/aclconf.h new file mode 100644 index 0000000000..639ce5686c --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/aclconf.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 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: aclconf.h,v 1.12.2.1 2004/03/09 06:09:21 marka Exp $ */ + +#ifndef NS_ACLCONF_H +#define NS_ACLCONF_H 1 + +#include + +#include + +#include + +typedef struct ns_aclconfctx { + ISC_LIST(dns_acl_t) named_acl_cache; +} ns_aclconfctx_t; + +/*** + *** Functions + ***/ + +ISC_LANG_BEGINDECLS + +void +ns_aclconfctx_init(ns_aclconfctx_t *ctx); +/* + * Initialize an ACL configuration context. + */ + +void +ns_aclconfctx_destroy(ns_aclconfctx_t *ctx); +/* + * Destroy an ACL configuration context. + */ + +isc_result_t +ns_acl_fromconfig(cfg_obj_t *caml, + cfg_obj_t *cctx, + ns_aclconfctx_t *ctx, + isc_mem_t *mctx, + dns_acl_t **target); +/* + * Construct a new dns_acl_t from configuration data in 'caml' and + * 'cctx'. Memory is allocated through 'mctx'. + * + * Any named ACLs referred to within 'caml' will be be converted + * inte nested dns_acl_t objects. Multiple references to the same + * named ACLs will be converted into shared references to a single + * nested dns_acl_t object when the referring objects were created + * passing the same ACL configuration context 'ctx'. + * + * On success, attach '*target' to the new dns_acl_t object. + */ + +ISC_LANG_ENDDECLS + +#endif /* NS_ACLCONF_H */ diff --git a/contrib/bind-9.2.4rc7/bin/named/include/named/client.h b/contrib/bind-9.2.4rc7/bin/named/include/named/client.h new file mode 100644 index 0000000000..3589c5b2ee --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/client.h @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 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: client.h,v 1.60.2.4 2004/07/23 02:57:01 marka Exp $ */ + +#ifndef NAMED_CLIENT_H +#define NAMED_CLIENT_H 1 + +/***** + ***** Module Info + *****/ + +/* + * Client + * + * 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: + * + * 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) + * + * 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 + +/*** + *** Types + ***/ + +typedef ISC_LIST(ns_client_t) client_list_t; + +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; + 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 recusive service */ +#define NS_CLIENTATTR_PKTINFO 0x04 /* pktinfo is valid */ +#define NS_CLIENTATTR_MULTICAST 0x08 /* recv'd from multicast */ + +/*** + *** 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. + */ + +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,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. + * + * Notes: + * 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: + * 'client' points to a valid client. + * 'acl' points to a valid ACL, or is NULL. + * + * Returns: + * ISC_R_SUCCESS if the request should be allowed + * ISC_R_REFUSED if the request should be denied + * No other return values are possible. + */ + +isc_result_t +ns_client_checkacl(ns_client_t *client, + const char *opname, dns_acl_t *acl, + isc_boolean_t default_allow, + int log_level); +/* + * Like ns_client_checkacl, but also logs the outcome of the + * check 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: + * Those of ns_client_checkaclsilent(), and: + * + * '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_aclmsg(const char *msg, dns_name_t *name, dns_rdataclass_t rdclass, + char *buf, size_t len); + +#endif /* NAMED_CLIENT_H */ diff --git a/contrib/bind-9.2.4rc7/bin/named/include/named/config.h b/contrib/bind-9.2.4rc7/bin/named/include/named/config.h new file mode 100644 index 0000000000..3d97be62c7 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/config.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001 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: config.h,v 1.4.2.1 2004/03/09 06:09:21 marka Exp $ */ + +#ifndef NAMED_CONFIG_H +#define NAMED_CONFIG_H 1 + +#include + +#include +#include + +isc_result_t +ns_config_parsedefaults(cfg_parser_t *parser, cfg_obj_t **conf); + +isc_result_t +ns_config_get(cfg_obj_t **maps, const char* name, cfg_obj_t **obj); + +int +ns_config_listcount(cfg_obj_t *list); + +isc_result_t +ns_config_getclass(cfg_obj_t *classobj, dns_rdataclass_t defclass, + dns_rdataclass_t *classp); + +dns_zonetype_t +ns_config_getzonetype(cfg_obj_t *zonetypeobj); + +isc_result_t +ns_config_getiplist(cfg_obj_t *config, 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(cfg_obj_t *config, 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(cfg_obj_t *config, in_port_t *portp); + +isc_result_t +ns_config_getkeyalgorithm(const char *str, dns_name_t **name); + +#endif /* NAMED_CONFIG_H */ diff --git a/contrib/bind-9.2.4rc7/bin/named/include/named/control.h b/contrib/bind-9.2.4rc7/bin/named/include/named/control.h new file mode 100644 index 0000000000..a805c00867 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/control.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001, 2003 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: control.h,v 1.6.2.3 2004/03/09 06:09:21 marka Exp $ */ + +#ifndef NAMED_CONTROL_H +#define NAMED_CONTROL_H 1 + +/* + * 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_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_STATUS "status" +#define NS_COMMAND_NULL "null" + +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, cfg_obj_t *config, + ns_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.2.4rc7/bin/named/include/named/globals.h b/contrib/bind-9.2.4rc7/bin/named/include/named/globals.h new file mode 100644 index 0000000000..d2a2250e92 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/globals.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 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: globals.h,v 1.59.2.1 2004/03/09 06:09:21 marka Exp $ */ + +#ifndef NAMED_GLOBALS_H +#define NAMED_GLOBALS_H 1 + +#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); +/* + * 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 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); + +/* + * 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); + +#undef EXTERN +#undef INIT + +#endif /* NAMED_GLOBALS_H */ diff --git a/contrib/bind-9.2.4rc7/bin/named/include/named/interfacemgr.h b/contrib/bind-9.2.4rc7/bin/named/include/named/interfacemgr.h new file mode 100644 index 0000000000..f0e339993a --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/interfacemgr.h @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 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: interfacemgr.h,v 1.23.2.1 2004/03/09 06:09:21 marka Exp $ */ + +#ifndef NAMED_INTERFACEMGR_H +#define NAMED_INTERFACEMGR_H 1 + +/***** + ***** Module Info + *****/ + +/* + * Interface manager + * + * The interface manager monitors the operating system's list + * of network interfaces, creating and destroying listeners + * as needed. + * + * Reliability: + * No impact expected. + * + * Resources: + * + * Security: + * The server will only be able to bind to the DNS port on + * newly discovered interfaces if it is running as root. + * + * Standards: + * 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) + +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. */ + 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_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. + */ + +#endif /* NAMED_INTERFACEMGR_H */ diff --git a/contrib/bind-9.2.4rc7/bin/named/include/named/listenlist.h b/contrib/bind-9.2.4rc7/bin/named/include/named/listenlist.h new file mode 100644 index 0000000000..af30de0dd3 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/listenlist.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 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: listenlist.h,v 1.10.2.1 2004/03/09 06:09:21 marka Exp $ */ + +#ifndef NAMED_LISTENLIST_H +#define NAMED_LISTENLIST_H 1 + +/***** + ***** Module Info + *****/ + +/* + * "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.2.4rc7/bin/named/include/named/log.h b/contrib/bind-9.2.4rc7/bin/named/include/named/log.h new file mode 100644 index 0000000000..f9b250a8c6 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/log.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 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: log.h,v 1.19.2.1 2004/03/09 06:09:22 marka Exp $ */ + +#ifndef NAMED_LOG_H +#define NAMED_LOG_H 1 + +#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]) + +/* + * 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.2.4rc7/bin/named/include/named/logconf.h b/contrib/bind-9.2.4rc7/bin/named/include/named/logconf.h new file mode 100644 index 0000000000..9e0dbf1a78 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/logconf.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 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: logconf.h,v 1.10.2.1 2004/03/09 06:09:22 marka Exp $ */ + +#ifndef NAMED_LOGCONF_H +#define NAMED_LOGCONF_H 1 + +#include + +isc_result_t +ns_log_configure(isc_logconfig_t *logconf, 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.2.4rc7/bin/named/include/named/lwaddr.h b/contrib/bind-9.2.4rc7/bin/named/include/named/lwaddr.h new file mode 100644 index 0000000000..ea7161ecfe --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/lwaddr.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 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: lwaddr.h,v 1.3.2.1 2004/03/09 06:09:22 marka Exp $ */ + +#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.2.4rc7/bin/named/include/named/lwdclient.h b/contrib/bind-9.2.4rc7/bin/named/include/named/lwdclient.h new file mode 100644 index 0000000000..047f98aac3 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/lwdclient.h @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 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: lwdclient.h,v 1.13.2.1 2004/03/09 06:09:22 marka Exp $ */ + +#ifndef NAMED_LWDCLIENT_H +#define NAMED_LWDCLIENT_H 1 + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#define LWRD_EVENTCLASS ISC_EVENTCLASS(4242) + +#define LWRD_SHUTDOWN (LWRD_EVENTCLASS + 0x0001) + +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) + +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.2.4rc7/bin/named/include/named/lwresd.h b/contrib/bind-9.2.4rc7/bin/named/include/named/lwresd.h new file mode 100644 index 0000000000..37af4d64ee --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/lwresd.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 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: lwresd.h,v 1.12.2.1 2004/03/09 06:09:22 marka Exp $ */ + +#ifndef NAMED_LWRESD_H +#define NAMED_LWRESD_H 1 + +#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, 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 + */ +isc_result_t +ns_lwdmanager_create(isc_mem_t *mctx, cfg_obj_t *lwres, ns_lwresd_t **lwresdp); + +void +ns_lwdmanager_attach(ns_lwresd_t *source, ns_lwresd_t **targetp); + +void +ns_lwdmanager_detach(ns_lwresd_t **lwresdp); + +/* + * Listener functions + */ +void +ns_lwreslistener_attach(ns_lwreslistener_t *source, + ns_lwreslistener_t **targetp); + +void +ns_lwreslistener_detach(ns_lwreslistener_t **listenerp); + +void +ns_lwreslistener_unlinkcm(ns_lwreslistener_t *listener, ns_lwdclientmgr_t *cm); + +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.2.4rc7/bin/named/include/named/lwsearch.h b/contrib/bind-9.2.4rc7/bin/named/include/named/lwsearch.h new file mode 100644 index 0000000000..9a7bb266a6 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/lwsearch.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 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: lwsearch.h,v 1.4.2.1 2004/03/09 06:09:22 marka Exp $ */ + +#ifndef NAMED_LWSEARCH_H +#define NAMED_LWSEARCH_H 1 + +#include +#include +#include + +#include + +#include + +/* + * 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. + */ + +struct ns_lwsearchlist { + unsigned int magic; + + isc_mutex_t lock; + isc_mem_t *mctx; + unsigned int refs; + dns_namelist_t names; +}; + +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.2.4rc7/bin/named/include/named/main.h b/contrib/bind-9.2.4rc7/bin/named/include/named/main.h new file mode 100644 index 0000000000..7c8d6cab62 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/main.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2002 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: main.h,v 1.8.2.3 2004/03/09 06:09:22 marka Exp $ */ + +#ifndef NAMED_MAIN_H +#define NAMED_MAIN_H 1 + +void +ns_main_earlyfatal(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +void +ns_main_earlywarning(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +#endif /* NAMED_MAIN_H */ diff --git a/contrib/bind-9.2.4rc7/bin/named/include/named/notify.h b/contrib/bind-9.2.4rc7/bin/named/include/named/notify.h new file mode 100644 index 0000000000..69a1ac4b2f --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/notify.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 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: notify.h,v 1.9.2.1 2004/03/09 06:09:23 marka Exp $ */ + +#ifndef NAMED_NOTIFY_H +#define NAMED_NOTIFY_H 1 + +#include +#include + +/*** + *** Module Info + ***/ + +/* + * RFC 1996 + * 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 apporiate 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 + * client to be valid. + */ + +#endif /* NAMED_NOTIFY_H */ + diff --git a/contrib/bind-9.2.4rc7/bin/named/include/named/query.h b/contrib/bind-9.2.4rc7/bin/named/include/named/query.h new file mode 100644 index 0000000000..4de0af36dc --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/query.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2002 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: query.h,v 1.28.2.4 2004/03/09 06:09:23 marka Exp $ */ + +#ifndef NAMED_QUERY_H +#define NAMED_QUERY_H 1 + +#include +#include +#include + +#include +#include + +#include + +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; + +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; + dns_fetch_t * fetch; + dns_a6context_t a6ctx; + isc_bufferlist_t namebufs; + ISC_LIST(ns_dbversion_t) activeversions; + ISC_LIST(ns_dbversion_t) freeversions; + /* + * Additional state used during IPv6 response synthesis only. + */ + struct { + isc_netaddr_t na; + } synth; +}; + +#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_WANTDNSSEC 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); + +#endif /* NAMED_QUERY_H */ diff --git a/contrib/bind-9.2.4rc7/bin/named/include/named/server.h b/contrib/bind-9.2.4rc7/bin/named/include/named/server.h new file mode 100644 index 0000000000..fc112d5ea8 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/server.h @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 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: server.h,v 1.58.2.3 2004/03/09 06:09:23 marka Exp $ */ + +#ifndef NAMED_SERVER_H +#define NAMED_SERVER_H 1 + +#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; + + /* + * 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_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 */ + + char * statsfile; /* Statistics file name */ + isc_uint64_t * querystats; /* Query statistics counters */ + + char * dumpfile; /* Dump file name */ + + ns_controls_t * controls; /* Control channels */ + unsigned int dispatchgen; + ns_dispatchlist_t dispatches; + +}; + +#define NS_SERVER_MAGIC ISC_MAGIC('S','V','E','R') +#define NS_SERVER_VALID(s) ISC_MAGIC_VALID(s, NS_SERVER_MAGIC) + +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); +/* + * 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_refreshcommand(ns_server_t *server, char *args); +/* + * Act on a "refresh" 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); + +/* + * 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); + +/* + * Report the server's status. + */ +isc_result_t +ns_server_status(ns_server_t *server, isc_buffer_t *text); + +/* + * Maintain a list of dispatches that require reserved ports. + */ +void +ns_add_reserved_dispatch(ns_server_t *server, isc_sockaddr_t *addr); + +#endif /* NAMED_SERVER_H */ diff --git a/contrib/bind-9.2.4rc7/bin/named/include/named/sortlist.h b/contrib/bind-9.2.4rc7/bin/named/include/named/sortlist.h new file mode 100644 index 0000000000..7b520b75b8 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/sortlist.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 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: sortlist.h,v 1.4.2.1 2004/03/09 06:09:23 marka Exp $ */ + +#ifndef NAMED_SORTLIST_H +#define NAMED_SORTLIST_H 1 + +#include + +#include + +/* + * Type for callback functions that rank addresses. + */ +typedef int +(*dns_addressorderfunc_t)(isc_netaddr_t *address, 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, 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(isc_netaddr_t *addr, 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(isc_netaddr_t *addr, 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, + 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.2.4rc7/bin/named/include/named/tkeyconf.h b/contrib/bind-9.2.4rc7/bin/named/include/named/tkeyconf.h new file mode 100644 index 0000000000..87ba18f9ee --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/tkeyconf.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 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: tkeyconf.h,v 1.9.2.1 2004/03/09 06:09:23 marka Exp $ */ + +#ifndef NS_TKEYCONF_H +#define NS_TKEYCONF_H 1 + +#include +#include + +#include + +ISC_LANG_BEGINDECLS + +isc_result_t +ns_tkeyctx_fromconfig(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: + * 'cfg' is a valid configuration options object. + * 'mctx' is not NULL + * 'ectx' is not NULL + * 'tctx' is not NULL + * '*tctx' is NULL + * + * Returns: + * ISC_R_SUCCESS + * ISC_R_NOMEMORY + */ + +ISC_LANG_ENDDECLS + +#endif /* NS_TKEYCONF_H */ diff --git a/contrib/bind-9.2.4rc7/bin/named/include/named/tsigconf.h b/contrib/bind-9.2.4rc7/bin/named/include/named/tsigconf.h new file mode 100644 index 0000000000..05f1a9ef3c --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/tsigconf.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 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: tsigconf.h,v 1.9.2.1 2004/03/09 06:09:23 marka Exp $ */ + +#ifndef NS_TSIGCONF_H +#define NS_TSIGCONF_H 1 + +#include +#include + +ISC_LANG_BEGINDECLS + +isc_result_t +ns_tsigkeyring_fromconfig(cfg_obj_t *config, 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: + * 'config' is not NULL. + * 'mctx' is not NULL + * 'ring' is not NULL, and '*ring' is NULL + * + * Returns: + * ISC_R_SUCCESS + * ISC_R_NOMEMORY + */ + +ISC_LANG_ENDDECLS + +#endif /* NS_TSIGCONF_H */ diff --git a/contrib/bind-9.2.4rc7/bin/named/include/named/types.h b/contrib/bind-9.2.4rc7/bin/named/include/named/types.h new file mode 100644 index 0000000000..f35c4c18d3 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/types.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 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: types.h,v 1.19.2.2 2004/03/09 06:09:23 marka Exp $ */ + +#ifndef NAMED_TYPES_H +#define NAMED_TYPES_H 1 + +#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_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; + +#endif /* NAMED_TYPES_H */ diff --git a/contrib/bind-9.2.4rc7/bin/named/include/named/update.h b/contrib/bind-9.2.4rc7/bin/named/include/named/update.h new file mode 100644 index 0000000000..e340d3cfe2 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/update.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 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: update.h,v 1.8.2.1 2004/03/09 06:09:23 marka Exp $ */ + +#ifndef NAMED_UPDATE_H +#define NAMED_UPDATE_H 1 + +/***** + ***** Module Info + *****/ + +/* + * 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.2.4rc7/bin/named/include/named/xfrout.h b/contrib/bind-9.2.4rc7/bin/named/include/named/xfrout.h new file mode 100644 index 0000000000..08638d49c7 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/xfrout.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 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: xfrout.h,v 1.7.2.1 2004/03/09 06:09:23 marka Exp $ */ + +#ifndef NAMED_XFROUT_H +#define NAMED_XFROUT_H 1 + +/***** + ***** Module Info + *****/ + +/* + * 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.2.4rc7/bin/named/include/named/zoneconf.h b/contrib/bind-9.2.4rc7/bin/named/include/named/zoneconf.h new file mode 100644 index 0000000000..a3437858a5 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/include/named/zoneconf.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2002 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: zoneconf.h,v 1.16.2.3 2004/03/09 06:09:23 marka Exp $ */ + +#ifndef NS_ZONECONF_H +#define NS_ZONECONF_H 1 + +#include +#include + +#include + +#include + +ISC_LANG_BEGINDECLS + +isc_result_t +ns_zone_configure(cfg_obj_t *config, cfg_obj_t *vconfig, cfg_obj_t *zconfig, + ns_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: + * 'lctx' to be initialized or NULL. + * 'cctx' to be initialized or NULL. + * 'ac' to point to an initialized ns_aclconfctx_t. + * 'czone' to be initialized. + * 'zone' to be initialized. + */ + +isc_boolean_t +ns_zone_reusable(dns_zone_t *zone, 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.2.4rc7/bin/named/interfacemgr.c b/contrib/bind-9.2.4rc7/bin/named/interfacemgr.c new file mode 100644 index 0000000000..96b7c7491a --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/interfacemgr.c @@ -0,0 +1,738 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2002 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: interfacemgr.c,v 1.59.2.7 2004/08/10 04:58:00 jinmei Exp $ */ + +#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 + +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. */ +}; + +static void +purge_old_interfaces(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); + + /* + * 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); + 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; + 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; + } + result = isc_socket_bind(ifp->tcpsocket, &ifp->addr); + 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, 3); + 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; + } + + 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_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; + + 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, 10, &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_result_t +do_ipv4(ns_interfacemgr_t *mgr) { + isc_interfaceiter_t *iter = NULL; + isc_result_t result; + + result = isc_interfaceiter_create(mgr->mctx, &iter); + if (result != ISC_R_SUCCESS) + return (result); + + 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; + + for (result = isc_interfaceiter_first(iter); + result == ISC_R_SUCCESS; + result = isc_interfaceiter_next(iter)) + { + ns_interface_t *ifp; + isc_interface_t interface; + ns_listenelt_t *le; + dns_aclelement_t elt; + unsigned int prefixlen; + + result = isc_interfaceiter_current(iter, &interface); + if (result != ISC_R_SUCCESS) + break; + + if (interface.address.family != AF_INET) + continue; + + if ((interface.flags & INTERFACE_F_UP) == 0) + continue; + + elt.type = dns_aclelementtype_ipprefix; + elt.negative = ISC_FALSE; + elt.u.ip_prefix.address = interface.address; + elt.u.ip_prefix.prefixlen = 32; + result = dns_acl_appendelement(mgr->aclenv.localhost, &elt); + if (result != ISC_R_SUCCESS) + goto ignore_interface; + + result = isc_netaddr_masktoprefixlen(&interface.netmask, + &prefixlen); + 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)); + } else { + elt.u.ip_prefix.prefixlen = prefixlen; + /* XXX suppress duplicates */ + result = dns_acl_appendelement(mgr->aclenv.localnets, + &elt); + if (result != ISC_R_SUCCESS) + goto ignore_interface; + } + + for (le = ISC_LIST_HEAD(mgr->listenon4->elts); + le != NULL; + le = ISC_LIST_NEXT(le, link)) + { + int match; + isc_netaddr_t listen_netaddr; + isc_sockaddr_t listen_sockaddr; + + /* + * Construct a socket address for this IP/port + * combination. + */ + isc_netaddr_fromin(&listen_netaddr, + &interface.address.type.in); + isc_sockaddr_fromnetaddr(&listen_sockaddr, + &listen_netaddr, + le->port); + + /* + * See if the address matches the listen-on statement; + * if not, ignore the interface. + */ + result = dns_acl_match(&listen_netaddr, NULL, + le->acl, &mgr->aclenv, + &match, NULL); + if (match <= 0) + continue; + + ifp = find_matching_interface(mgr, &listen_sockaddr); + if (ifp != NULL) { + ifp->generation = mgr->generation; + } else { + char sabuf[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_format(&listen_sockaddr, + sabuf, sizeof(sabuf)); + isc_log_write(IFMGR_COMMON_LOGARGS, + ISC_LOG_INFO, + "listening on IPv4 interface " + "%s, %s", interface.name, sabuf); + + result = ns_interface_setup(mgr, + &listen_sockaddr, + interface.name, + &ifp); + if (result != ISC_R_SUCCESS) { + isc_log_write(IFMGR_COMMON_LOGARGS, + ISC_LOG_ERROR, + "creating IPv4 interface %s " + "failed; interface ignored", + interface.name); + } + /* Continue. */ + } + + } + continue; + + ignore_interface: + isc_log_write(IFMGR_COMMON_LOGARGS, + ISC_LOG_ERROR, + "ignoring IPv4 interface %s: %s", + interface.name, isc_result_totext(result)); + continue; + } + if (result != ISC_R_NOMORE) + UNEXPECTED_ERROR(__FILE__, __LINE__, + "IPv4: interface iteration failed: %s", + isc_result_totext(result)); + else + result = ISC_R_SUCCESS; + cleanup_iter: + isc_interfaceiter_destroy(&iter); + return (result); +} + +static isc_boolean_t +listenon_is_ip6_none(ns_listenelt_t *elt) { + if (elt->acl->length == 0) + return (ISC_TRUE); /* listen-on-v6 { } */ + if (elt->acl->length > 1) + return (ISC_FALSE); /* listen-on-v6 { ...; ...; } */ + if (elt->acl->elements[0].negative == ISC_TRUE && + elt->acl->elements[0].type == dns_aclelementtype_any) + return (ISC_TRUE); /* listen-on-v6 { none; } */ + return (ISC_FALSE); /* All others */ +} + +static isc_boolean_t +listenon_is_ip6_any(ns_listenelt_t *elt) { + if (elt->acl->length != 1) + return (ISC_FALSE); + if (elt->acl->elements[0].negative == ISC_FALSE && + elt->acl->elements[0].type == dns_aclelementtype_any) + return (ISC_TRUE); /* listen-on-v6 { any; } */ + return (ISC_FALSE); /* All others */ +} + +static isc_result_t +do_ipv6(ns_interfacemgr_t *mgr) { + isc_result_t result; + ns_interface_t *ifp; + isc_sockaddr_t listen_addr; + struct in6_addr in6a; + ns_listenelt_t *le; + + for (le = ISC_LIST_HEAD(mgr->listenon6->elts); + le != NULL; + le = ISC_LIST_NEXT(le, link)) + { + if (listenon_is_ip6_none(le)) + continue; + if (! listenon_is_ip6_any(le)) { + isc_log_write(IFMGR_COMMON_LOGARGS, + ISC_LOG_ERROR, + "bad IPv6 listen-on list: " + "must be 'any' or 'none'"); + return (ISC_R_FAILURE); + } + + 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); + if (result != ISC_R_SUCCESS) { + isc_log_write(IFMGR_COMMON_LOGARGS, + ISC_LOG_ERROR, + "listening on IPv6 interfaces " + "failed"); + /* Continue. */ + } + } + } + return (ISC_R_SUCCESS); +} + +void +ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) { + isc_boolean_t purge = ISC_TRUE; + + REQUIRE(NS_INTERFACEMGR_VALID(mgr)); + + mgr->generation++; /* Increment the generation count. */ + + if (isc_net_probeipv6() == ISC_R_SUCCESS) { + if (do_ipv6(mgr) != ISC_R_SUCCESS) + purge = ISC_FALSE; + } +#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) { + if (do_ipv4(mgr) != ISC_R_SUCCESS) + purge = ISC_FALSE; + } else + isc_log_write(IFMGR_COMMON_LOGARGS, + verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1), + "no IPv4 interfaces found"); + + /* + * 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 (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_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); +} + diff --git a/contrib/bind-9.2.4rc7/bin/named/listenlist.c b/contrib/bind-9.2.4rc7/bin/named/listenlist.c new file mode 100644 index 0000000000..dbc24cb517 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/listenlist.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 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: listenlist.c,v 1.9.2.1 2004/03/09 06:09:18 marka Exp $ */ + +#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.2.4rc7/bin/named/log.c b/contrib/bind-9.2.4rc7/bin/named/log.c new file mode 100644 index 0000000000..6cd92b963b --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/log.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 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: log.c,v 1.33.2.2 2004/03/09 06:09:18 marka Exp $ */ + +#include + +#include + +#include + +#include + +/* + * When adding a new category, be sure to add the appropriate + * #define to . + */ +static isc_logcategory_t categories[] = { + { "", 0 }, + { "client", 0 }, + { "network", 0 }, + { "update", 0 }, + { "queries", 0 }, + { "unmatched", 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); + + 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 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; + } + + /* + * 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 (! 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); + } + + 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.2.4rc7/bin/named/logconf.c b/contrib/bind-9.2.4rc7/bin/named/logconf.c new file mode 100644 index 0000000000..6e87d5cd46 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/logconf.c @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 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: logconf.c,v 1.30.2.5 2004/03/09 06:09:18 marka Exp $ */ + +#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(cfg_obj_t *ccat, isc_logconfig_t *lctx) { + isc_result_t result; + const char *catname; + isc_logcategory_t *category; + isc_logmodule_t *module; + cfg_obj_t *destinations = NULL; + 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)) + { + cfg_obj_t *channel = cfg_listelt_value(element); + 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(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; + cfg_obj_t *fileobj = NULL; + cfg_obj_t *syslogobj = NULL; + cfg_obj_t *nullobj = NULL; + cfg_obj_t *stderrobj = NULL; + 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) { + cfg_obj_t *pathobj = cfg_tuple_get(fileobj, "file"); + cfg_obj_t *sizeobj = cfg_tuple_get(fileobj, "size"); + 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)) { + 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. + */ + { + cfg_obj_t *printcat = NULL; + cfg_obj_t *printsev = NULL; + 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)) { + 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, cfg_obj_t *logstmt) { + isc_result_t result; + cfg_obj_t *channels = NULL; + cfg_obj_t *categories = NULL; + cfg_listelt_t *element; + isc_boolean_t default_set = ISC_FALSE; + isc_boolean_t unmatched_set = ISC_FALSE; + + 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)) + { + 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)) + { + cfg_obj_t *category = cfg_listelt_value(element); + CHECK(category_fromconf(category, logconf)); + if (!default_set) { + cfg_obj_t *catname = cfg_tuple_get(category, "name"); + if (strcmp(cfg_obj_asstring(catname), "default") == 0) + default_set = ISC_TRUE; + } + if (!unmatched_set) { + cfg_obj_t *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.2.4rc7/bin/named/lwaddr.c b/contrib/bind-9.2.4rc7/bin/named/lwaddr.c new file mode 100644 index 0000000000..54415498fa --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/lwaddr.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 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: lwaddr.c,v 1.3.2.1 2004/03/09 06:09:18 marka Exp $ */ + +#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.in, 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.2.4rc7/bin/named/lwdclient.c b/contrib/bind-9.2.4rc7/bin/named/lwdclient.c new file mode 100644 index 0000000000..67c3a88333 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/lwdclient.c @@ -0,0 +1,450 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 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: lwdclient.c,v 1.13.2.1 2004/03/09 06:09:18 marka Exp $ */ + +#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; + + /* + * 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) { + 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; + + ns_lwdclient_startrecv(cm); + + 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; + + 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); + + ns_lwdclient_startrecv(cm); +} + +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.2.4rc7/bin/named/lwderror.c b/contrib/bind-9.2.4rc7/bin/named/lwderror.c new file mode 100644 index 0000000000..6a4c15b5e3 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/lwderror.c @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 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: lwderror.c,v 1.7.2.1 2004/03/09 06:09:18 marka Exp $ */ + +#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.2.4rc7/bin/named/lwdgabn.c b/contrib/bind-9.2.4rc7/bin/named/lwdgabn.c new file mode 100644 index 0000000000..d53a5df728 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/lwdgabn.c @@ -0,0 +1,655 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 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: lwdgabn.c,v 1.13.2.1 2004/03/09 06:09:18 marka Exp $ */ + +#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; + 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, 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.2.4rc7/bin/named/lwdgnba.c b/contrib/bind-9.2.4rc7/bin/named/lwdgnba.c new file mode 100644 index 0000000000..4d3fe96722 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/lwdgnba.c @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001, 2003 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: lwdgnba.c,v 1.13.2.3 2004/03/09 06:09:18 marka Exp $ */ + +#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_IPV6NIBBLE) == 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 nibble then IP6.ARPA bitstring. + */ + if ((client->options & DNS_BYADDROPT_IPV6INT) == 0) + client->options |= DNS_BYADDROPT_IPV6INT; + else + client->options &= ~DNS_BYADDROPT_IPV6NIBBLE; + + 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; + if (req->addr.address == NULL) + goto out; + + /* + * Start with IP6.ARPA NIBBLE lookups. + */ + client->options = DNS_BYADDROPT_IPV6NIBBLE; + 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); + + /* + * 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.2.4rc7/bin/named/lwdgrbn.c b/contrib/bind-9.2.4rc7/bin/named/lwdgrbn.c new file mode 100644 index 0000000000..a6365ff56f --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/lwdgrbn.c @@ -0,0 +1,513 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 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: lwdgrbn.c,v 1.11.2.1 2004/03/09 06:09:18 marka Exp $ */ + +#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_sig) { + 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)); + if (newlens != NULL) + isc_mem_put(mctx, newlens, used * sizeof(*oldlens)); + 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 out; + + 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)); + + 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.2.4rc7/bin/named/lwdnoop.c b/contrib/bind-9.2.4rc7/bin/named/lwdnoop.c new file mode 100644 index 0000000000..cfaea2058b --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/lwdnoop.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 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: lwdnoop.c,v 1.6.2.1 2004/03/09 06:09:18 marka Exp $ */ + +#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 out; + + 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 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; + + /* + * We can now destroy request. + */ + lwres_nooprequest_free(client->clientmgr->lwctx, &req); + + NS_LWDCLIENT_SETSEND(client); + + return; + + out: + if (req != NULL) + lwres_nooprequest_free(client->clientmgr->lwctx, &req); + + if (lwb.base != NULL) + lwres_context_freemem(client->clientmgr->lwctx, + lwb.base, lwb.length); + + ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); +} diff --git a/contrib/bind-9.2.4rc7/bin/named/lwresd.8 b/contrib/bind-9.2.4rc7/bin/named/lwresd.8 new file mode 100644 index 0000000000..db76a07a4e --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/lwresd.8 @@ -0,0 +1,140 @@ +.\" Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2000, 2001 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: lwresd.8,v 1.13.2.2 2004/06/03 05:21:13 marka Exp $ +.\" +.TH "LWRESD" "8" "June 30, 2000" "BIND9" "" +.SH NAME +lwresd \- lightweight resolver daemon +.SH SYNOPSIS +.sp +\fBlwresd\fR [ \fB-C \fIconfig-file\fB\fR ] [ \fB-d \fIdebug-level\fB\fR ] [ \fB-f\fR ] [ \fB-g\fR ] [ \fB-i \fIpid-file\fB\fR ] [ \fB-n \fI#cpus\fB\fR ] [ \fB-P \fIport\fB\fR ] [ \fB-p \fIport\fB\fR ] [ \fB-s\fR ] [ \fB-t \fIdirectory\fB\fR ] [ \fB-u \fIuser\fB\fR ] [ \fB-v\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" +.TP +\fB-C \fIconfig-file\fB\fR +Use \fIconfig-file\fR as the +configuration file instead of the default, +\fI/etc/resolv.conf\fR. +.TP +\fB-d \fIdebug-level\fB\fR +Set the daemon's debug level to \fIdebug-level\fR. +Debugging traces from \fBlwresd\fR become +more verbose as the debug level increases. +.TP +\fB-f\fR +Run the server in the foreground (i.e. do not daemonize). +.TP +\fB-g\fR +Run the server in the foreground and force all logging +to \fIstderr\fR. +.TP +\fB-n \fI#cpus\fB\fR +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. +.TP +\fB-P \fIport\fB\fR +Listen for lightweight resolver queries on port +\fIport\fR. If +not specified, the default is port 921. +.TP +\fB-p \fIport\fB\fR +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. +.TP +\fB-s\fR +Write memory usage statistics to \fIstdout\fR +on exit. +.sp +.RS +.B "Note:" +This option is mainly of interest to BIND 9 developers +and may be removed or changed in a future release. +.RE +.sp +.TP +\fB-t \fIdirectory\fB\fR +\fBchroot()\fR to \fIdirectory\fR after +processing the command line arguments, but before +reading the configuration file. +.sp +.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()\fR is +defined allows a process with root privileges to +escape a chroot jail. +.RE +.sp +.TP +\fB-u \fIuser\fB\fR +\fBsetuid()\fR to \fIuser\fR after completing +privileged operations, such as creating sockets that +listen on privileged ports. +.TP +\fB-v\fR +Report the version number and exit. +.SH "FILES" +.TP +\fB\fI/etc/resolv.conf\fB\fR +The default configuration file. +.TP +\fB\fI/var/run/lwresd.pid\fB\fR +The default process-id file. +.SH "SEE ALSO" +.PP +\fBnamed\fR(8), +\fBlwres\fR(3), +\fBresolver\fR(5). +.SH "AUTHOR" +.PP +Internet Systems Consortium diff --git a/contrib/bind-9.2.4rc7/bin/named/lwresd.c b/contrib/bind-9.2.4rc7/bin/named/lwresd.c new file mode 100644 index 0000000000..eb5687f289 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/lwresd.c @@ -0,0 +1,855 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001, 2003 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: lwresd.c,v 1.37.2.3 2004/03/09 06:09:19 marka Exp $ */ + +/* + * 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, cfg_obj_t *lwres, + ns_lwresd_t **lwresdp) +{ + ns_lwresd_t *lwresd; + const char *vname; + dns_rdataclass_t vclass; + cfg_obj_t *obj, *viewobj, *searchobj; + 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; + 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)) + { + cfg_obj_t *search; + 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); + 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; + + REQUIRE(listenerp != NULL && *listenerp == NULL); + + listener = isc_mem_get(mctx, sizeof(ns_lwreslistener_t)); + if (listener == NULL) + return (ISC_R_NOMEMORY); + RUNTIME_CHECK(isc_mutex_init(&listener->lock) == ISC_R_SUCCESS); + + 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); + 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) { + ns_lwdclient_startrecv(cm); + 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, cfg_obj_t *config) { + cfg_obj_t *lwreslist = NULL; + cfg_obj_t *lwres = NULL; + cfg_obj_t *listenerslist = NULL; + 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; + 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.2.4rc7/bin/named/lwresd.html b/contrib/bind-9.2.4rc7/bin/named/lwresd.html new file mode 100644 index 0000000000..8ac46ac9b3 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/lwresd.html @@ -0,0 +1,541 @@ + + + + +lwresd

lwresd

Name

lwresd -- lightweight resolver daemon

Synopsis

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

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

-C config-file

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

-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. +

-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() 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.2.4rc7/bin/named/lwsearch.c b/contrib/bind-9.2.4rc7/bin/named/lwsearch.c new file mode 100644 index 0000000000..433f40e2ab --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/lwsearch.c @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 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: lwsearch.c,v 1.7.2.1 2004/03/09 06:09:19 marka Exp $ */ + +#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; + + REQUIRE(mctx != NULL); + REQUIRE(listp != NULL && *listp == NULL); + + list = isc_mem_get(mctx, sizeof(ns_lwsearchlist_t)); + if (list == NULL) + return (ISC_R_NOMEMORY); + + RUNTIME_CHECK(isc_mutex_init(&list->lock) == ISC_R_SUCCESS); + 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.2.4rc7/bin/named/main.c b/contrib/bind-9.2.4rc7/bin/named/main.c new file mode 100644 index 0000000000..9c772c8f83 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/main.c @@ -0,0 +1,656 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2003 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: main.c,v 1.119.2.10 2004/04/20 13:54:17 marka Exp $ */ + +#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 /* Explicit, though named/log.h includes it. */ +#include +#include +#include +#include +#include +#include + +/* + * Include header files for database drivers here. + */ +/* #include "xxdb.h" */ + +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]; + +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 assetion 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 [-c conffile | -C resolvconffile] " + "[-d debuglevel] [-f|-g]\n" + " [-n number_of_cpus] [-p port]" + "[-P listen-port] [-s]\n" + " [-t chrootdir] [-u username] [-i pidfile]\n"); +} + +static void +usage(void) { + if (ns_g_lwresdonly) { + lwresd_usage(); + return; + } + fprintf(stderr, + "usage: named [-c conffile] [-d debuglevel] " + "[-f|-g] [-n number_of_cpus]\n" + " [-p port] [-s] [-t chrootdir] [-u username]\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 void +parse_command_line(int argc, char *argv[]) { + int ch; + int port; + + save_command_line(argc, argv); + + isc_commandline_errprint = ISC_FALSE; + while ((ch = isc_commandline_parse(argc, argv, + "c:C:d:fgi:ln:N:p:P:st:u:vx:")) != + -1) { + switch (ch) { + 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 '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 '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(); + 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; + +#ifdef ISC_PLATFORM_USETHREADS + if (ns_g_cpus == 0) + ns_g_cpus = isc_os_ncpus(); +#else + ns_g_cpus = 1; +#endif + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, + ISC_LOG_INFO, "using %u CPU%s", + ns_g_cpus, ns_g_cpus == 1 ? "" : "s"); + result = isc_taskmgr_create(ns_g_mctx, ns_g_cpus, 0, &ns_g_taskmgr); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "ns_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__, + "ns_timermgr_create() failed: %s", + isc_result_totext(result)); + return (ISC_R_UNEXPECTED); + } + + result = isc_socketmgr_create(ns_g_mctx, &ns_g_socketmgr); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_socketmgr_create() failed: %s", + isc_result_totext(result)); + return (ISC_R_UNEXPECTED); + } + + 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); + /* + * 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; + + /* + * 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(); + + 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(); + + 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); + + /* + * 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; + } + + result = create_managers(); + if (result != ISC_R_SUCCESS) + ns_main_earlyfatal("create_managers() failed: %s", + isc_result_totext(result)); + + /* + * Add calls to register sdb drivers here. + */ + /* xxdb_init(); */ + + ns_server_create(ns_g_mctx, &ns_g_server); +} + +static void +cleanup(void) { + destroy_managers(); + + ns_server_destroy(&ns_g_server); + + /* + * Add calls to unregister sdb drivers here. + */ + /* xxdb_clear(); */ + + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, + ISC_LOG_NOTICE, "exiting"); + ns_log_shutdown(); +} + +int +main(int argc, char *argv[]) { + isc_result_t result; + + /* + * Record version in core image. + * strings named.core | grep "named version:" + */ +#ifdef __DATE__ + strncat(version, "named version: BIND " VERSION " (" __DATE__ ")", + sizeof(version)); +#else + strncat(version, "named version: BIND " VERSION, sizeof(version)); +#endif + version[sizeof(version) - 1] = '\0'; + 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); + + result = isc_app_start(); + if (result != ISC_R_SUCCESS) + ns_main_earlyfatal("isc_app_start() failed: %s", + isc_result_totext(result)); + + 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)); + + dns_result_register(); + dst_result_register(); + isccc_result_register(); + + parse_command_line(argc, argv); + + 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); + + cleanup(); + + if (want_stats) { + isc_mem_stats(ns_g_mctx, stdout); + isc_mutex_stats(stdout); + } + isc_mem_destroy(&ns_g_mctx); + + isc_app_finish(); + + ns_os_closedevnull(); + + ns_os_shutdown(); + + return (0); +} diff --git a/contrib/bind-9.2.4rc7/bin/named/named.8 b/contrib/bind-9.2.4rc7/bin/named/named.8 new file mode 100644 index 0000000000..712e1ece07 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/named.8 @@ -0,0 +1,167 @@ +.\" Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2000, 2001 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: named.8,v 1.17.2.2 2004/06/03 05:21:13 marka Exp $ +.\" +.TH "NAMED" "8" "June 30, 2000" "BIND9" "" +.SH NAME +named \- Internet domain name server +.SH SYNOPSIS +.sp +\fBnamed\fR [ \fB-c \fIconfig-file\fB\fR ] [ \fB-d \fIdebug-level\fB\fR ] [ \fB-f\fR ] [ \fB-g\fR ] [ \fB-n \fI#cpus\fB\fR ] [ \fB-p \fIport\fB\fR ] [ \fB-s\fR ] [ \fB-t \fIdirectory\fB\fR ] [ \fB-u \fIuser\fB\fR ] [ \fB-v\fR ] [ \fB-x \fIcache-file\fB\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" +.TP +\fB-c \fIconfig-file\fB\fR +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. +.TP +\fB-d \fIdebug-level\fB\fR +Set the daemon's debug level to \fIdebug-level\fR. +Debugging traces from \fBnamed\fR become +more verbose as the debug level increases. +.TP +\fB-f\fR +Run the server in the foreground (i.e. do not daemonize). +.TP +\fB-g\fR +Run the server in the foreground and force all logging +to \fIstderr\fR. +.TP +\fB-n \fI#cpus\fB\fR +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. +.TP +\fB-p \fIport\fB\fR +Listen for queries on port \fIport\fR. If not +specified, the default is port 53. +.TP +\fB-s\fR +Write memory usage statistics to \fIstdout\fR on exit. +.sp +.RS +.B "Note:" +This option is mainly of interest to BIND 9 developers +and may be removed or changed in a future release. +.RE +.sp +.TP +\fB-t \fIdirectory\fB\fR +\fBchroot()\fR to \fIdirectory\fR after +processing the command line arguments, but before +reading the configuration file. +.sp +.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()\fR is +defined allows a process with root privileges to +escape a chroot jail. +.RE +.sp +.TP +\fB-u \fIuser\fB\fR +\fBsetuid()\fR to \fIuser\fR after completing +privileged operations, such as creating sockets that +listen on privileged ports. +.sp +.RS +.B "Note:" +On Linux, \fBnamed\fR uses the kernel's +capability mechanism to drop all root privileges +except the ability to \fBbind()\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()\fR. +.RE +.sp +.TP +\fB-v\fR +Report the version number and exit. +.TP +\fB-x \fIcache-file\fB\fR +Load data from \fIcache-file\fR into the +cache of the default view. +.sp +.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 +.sp +.SH "SIGNALS" +.PP +In routine operation, signals should not be used to control +the nameserver; \fBrndc\fR should be used +instead. +.TP +\fBSIGHUP\fR +Force a reload of the server. +.TP +\fBSIGINT, SIGTERM\fR +Shut down the server. +.PP +The result of sending any other signals to the server is undefined. +.PP +.SH "CONFIGURATION" +.PP +The \fBnamed\fR configuration file is too complex +to describe in detail here. A complete description is +provided in the \fIBIND 9 Administrator Reference +Manual\fR. +.SH "FILES" +.TP +\fB\fI/etc/named.conf\fB\fR +The default configuration file. +.TP +\fB\fI/var/run/named.pid\fB\fR +The default process-id file. +.SH "SEE ALSO" +.PP +\fIRFC 1033\fR, +\fIRFC 1034\fR, +\fIRFC 1035\fR, +\fBrndc\fR(8), +\fBlwresd\fR(8), +\fIBIND 9 Administrator Reference Manual\fR. +.SH "AUTHOR" +.PP +Internet Systems Consortium diff --git a/contrib/bind-9.2.4rc7/bin/named/named.html b/contrib/bind-9.2.4rc7/bin/named/named.html new file mode 100644 index 0000000000..f1fa281830 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/named.html @@ -0,0 +1,633 @@ + + + + +named

named

Name

named -- Internet domain name server

Synopsis

named [-c config-file] [-d debug-level] [-f] [-g] [-n #cpus] [-p port] [-s] [-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

-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. +

-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. +

-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() 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() 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(). +

-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, + rndc(8), + lwresd(8), + BIND 9 Administrator Reference Manual. +

AUTHOR

Internet Systems Consortium +

diff --git a/contrib/bind-9.2.4rc7/bin/named/notify.c b/contrib/bind-9.2.4rc7/bin/named/notify.c new file mode 100644 index 0000000000..3d23c08bd7 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/notify.c @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001, 2003 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: notify.c,v 1.24.2.3 2004/03/09 06:09:19 marka Exp $ */ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * This module implements notify as in RFC 1996. + */ + +static void +notify_log(int level, const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + isc_log_vwrite(ns_g_lctx, 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 str[DNS_NAME_FORMATSIZE]; + + /* + * Interpret the question section. + */ + result = dns_message_firstname(request, DNS_SECTION_QUESTION); + if (result != ISC_R_SUCCESS) { + notify_log(ISC_LOG_INFO, "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(ISC_LOG_INFO, + "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(ISC_LOG_INFO, + "notify question section contains multiple RRs"); + goto failure; + } + + /* The one rdataset must be an SOA. */ + if (zone_rdataset->type != dns_rdatatype_soa) { + notify_log(ISC_LOG_INFO, + "notify question section contains no SOA"); + goto formerr; + } + + dns_name_format(zonename, str, sizeof(str)); + 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(ISC_LOG_INFO, "received notify for zone '%s'", str); + respond(client, dns_zone_notifyreceive(zone, + ns_client_getsockaddr(client), request)); + break; + default: + goto notauth; + } + dns_zone_detach(&zone); + return; + + notauth: + notify_log(ISC_LOG_INFO, + "received notify for zone '%s': not authoritative", + str); + 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.2.4rc7/bin/named/query.c b/contrib/bind-9.2.4rc7/bin/named/query.c new file mode 100644 index 0000000000..4c67fff0b9 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/query.c @@ -0,0 +1,3899 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2003 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: query.c,v 1.198.2.19 2004/04/15 02:16:25 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 + +#define PARTIALANSWER(c) (((c)->query.attributes & \ + NS_QUERYATTR_PARTIALANSWER) != 0) +#define USECACHE(c) (((c)->query.attributes & \ + NS_QUERYATTR_CACHEOK) != 0) +#define RECURSIONOK(c) (((c)->query.attributes & \ + NS_QUERYATTR_RECURSIONOK) != 0) +#define RECURSING(c) (((c)->query.attributes & \ + NS_QUERYATTR_RECURSING) != 0) +#define CACHEGLUEOK(c) (((c)->query.attributes & \ + NS_QUERYATTR_CACHEGLUEOK) != 0) +#define WANTRECURSION(c) (((c)->query.attributes & \ + NS_QUERYATTR_WANTRECURSION) != 0) +#define WANTDNSSEC(c) (((c)->query.attributes & \ + NS_QUERYATTR_WANTDNSSEC) != 0) +#define NOAUTHORITY(c) (((c)->query.attributes & \ + NS_QUERYATTR_NOAUTHORITY) != 0) +#define NOADDITIONAL(c) (((c)->query.attributes & \ + NS_QUERYATTR_NOADDITIONAL) != 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 + +static unsigned char ip6int_ndata[] = "\003ip6\003int"; +static unsigned char ip6int_offsets[] = { 0, 4, 8 }; + +static dns_name_t ip6int_name = { + DNS_NAME_MAGIC, + ip6int_ndata, 9, 3, + DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, + ip6int_offsets, NULL, + {(void *)-1, (void *)-1}, + {NULL, NULL} +}; + +static isc_result_t +query_simplefind(void *arg, dns_name_t *name, dns_rdatatype_t type, + isc_stdtime_t now, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset); + +static inline void +query_adda6rrset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset); + +static void +query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype); + +static void +synth_fwd_start(ns_client_t *client); + +static void +synth_fwd_startfind(ns_client_t *client); + +static void +synth_fwd_respond(ns_client_t *client, dns_adbfind_t *find); + +static void +synth_fwd_finddone(isc_task_t *task, isc_event_t *ev); + +static void +synth_finish(ns_client_t *client, isc_result_t result); + +static void +synth_rev_start(ns_client_t *client); + +static void +synth_rev_byaddrdone_arpa(isc_task_t *task, isc_event_t *event); + +static void +synth_rev_byaddrdone_int(isc_task_t *task, isc_event_t *event); + +static void +synth_rev_respond(ns_client_t *client, dns_byaddrevent_t *bevent); + +/* + * Increment query statistics counters. + */ +static inline void +inc_stats(ns_client_t *client, dns_statscounter_t counter) { + dns_zone_t *zone = client->query.authzone; + + REQUIRE(counter < DNS_STATS_NCOUNTERS); + + ns_g_server->querystats[counter]++; + + if (zone != NULL) { + isc_uint64_t *zonestats = dns_zone_getstatscounters(zone); + if (zonestats != NULL) + zonestats[counter]++; + } +} + +static void +query_send(ns_client_t *client) { + dns_statscounter_t counter; + if (client->message->rcode == dns_rcode_noerror) { + if (ISC_LIST_EMPTY(client->message->sections[DNS_SECTION_ANSWER])) { + if (client->query.isreferral) { + counter = dns_statscounter_referral; + } else { + counter = dns_statscounter_nxrrset; + } + } else { + counter = dns_statscounter_success; + } + } else if (client->message->rcode == dns_rcode_nxdomain) { + counter = dns_statscounter_nxdomain; + } else { + /* We end up here in case of YXDOMAIN, and maybe others */ + counter = dns_statscounter_failure; + } + inc_stats(client, counter); + ns_client_send(client); +} + +static void +query_error(ns_client_t *client, isc_result_t result) { + inc_stats(client, dns_statscounter_failure); + ns_client_error(client, result); +} + +static void +query_next(ns_client_t *client, isc_result_t result) { + inc_stats(client, dns_statscounter_failure); + ns_client_next(client, result); +} + +static inline void +query_maybeputqname(ns_client_t *client) { + if (client->query.restarts > 0) { + /* + * client->query.qname was dynamically allocated. + */ + dns_message_puttempname(client->message, + &client->query.qname); + client->query.qname = NULL; + } +} + +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; + unsigned int i; + + /* + * Reset the query state of a client to its default state. + */ + + /* + * Cancel the fetch if it's running. + */ + if (client->query.fetch != NULL) { + dns_resolver_cancelfetch(client->query.fetch); + + client->query.fetch = NULL; + } + + /* + * 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); + + /* + * Clean up free versions. + */ + 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); + } + } + + 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); + } + } + + query_maybeputqname(client); + + client->query.attributes = (NS_QUERYATTR_RECURSIONOK | + NS_QUERYATTR_CACHEOK); + 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; + 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) + return (result); + dns_a6_init(&client->query.a6ctx, query_simplefind, query_adda6rrset, + NULL, NULL, client); + return (query_newnamebuf(client)); +} + +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_getzonedb(ns_client_t *client, dns_name_t *name, unsigned int options, + dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp) +{ + isc_result_t result; + isc_boolean_t check_acl, new_zone; + dns_acl_t *queryacl; + ns_dbversion_t *dbversion; + unsigned int ztoptions; + dns_zone_t *zone = NULL; + dns_db_t *db = NULL; + + 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 == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) + result = dns_zone_getdb(zone, &db); + + if (result != ISC_R_SUCCESS) + goto fail; + + /* + * 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, queryacl, ISC_TRUE); + if (log) { + char msg[DNS_NAME_FORMATSIZE + DNS_RDATACLASS_FORMATSIZE + + sizeof "query '/'"]; + if (result == ISC_R_SUCCESS) { + if (isc_log_wouldlog(ns_g_lctx, + ISC_LOG_DEBUG(3))) + { + ns_client_aclmsg("query", name, + 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, + 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. */ + *zonep = zone; + *dbp = db; + *versionp = dbversion->version; + + return (ISC_R_SUCCESS); + + refuse: + result = DNS_R_REFUSED; + 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_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); + + result = ns_client_checkacl(client, "query (cache)", + client->view->queryacl, + ISC_TRUE, + log ? ISC_LOG_INFO : + ISC_LOG_DEBUG(3)); + 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. */ + + /* 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, unsigned int options, + dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp, + isc_boolean_t *is_zonep) +{ + isc_result_t result; + + result = query_getzonedb(client, name, options, zonep, dbp, versionp); + if (result == ISC_R_SUCCESS) { + *is_zonep = ISC_TRUE; + } else if (result == ISC_R_NOTFOUND) { + result = query_getcachedb(client, dbp, options); + *is_zonep = ISC_FALSE; + } + return (result); +} + +static isc_result_t +query_simplefind(void *arg, dns_name_t *name, dns_rdatatype_t type, + isc_stdtime_t now, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) +{ + ns_client_t *client = arg; + isc_result_t result; + dns_fixedname_t foundname; + dns_db_t *db; + dns_dbversion_t *version; + unsigned int dboptions; + isc_boolean_t is_zone; + dns_rdataset_t zrdataset, zsigrdataset; + dns_zone_t *zone; + + REQUIRE(NS_CLIENT_VALID(client)); + REQUIRE(rdataset != NULL); + + dns_rdataset_init(&zrdataset); + if (sigrdataset != NULL) + dns_rdataset_init(&zsigrdataset); + + /* + * Find a database to answer the query. + */ + zone = NULL; + db = NULL; + version = NULL; + result = query_getdb(client, name, 0, &zone, &db, &version, &is_zone); + if (result != ISC_R_SUCCESS) + goto cleanup; + + db_find: + /* + * Now look for an answer in the database. + */ + dns_fixedname_init(&foundname); + dboptions = client->query.dboptions; + if (db == client->query.gluedb || (!is_zone && CACHEGLUEOK(client))) + dboptions |= DNS_DBFIND_GLUEOK; + result = dns_db_find(db, name, version, type, dboptions, + now, NULL, dns_fixedname_name(&foundname), + rdataset, sigrdataset); + if (result == DNS_R_DELEGATION || + result == ISC_R_NOTFOUND) { + if (dns_rdataset_isassociated(rdataset)) + dns_rdataset_disassociate(rdataset); + if (sigrdataset != NULL && + dns_rdataset_isassociated(sigrdataset)) + dns_rdataset_disassociate(sigrdataset); + if (is_zone) { + if (USECACHE(client)) { + /* + * Either the answer is in the cache, or we + * don't know it. + */ + is_zone = ISC_FALSE; + version = NULL; + dns_db_detach(&db); + dns_db_attach(client->view->cachedb, &db); + goto db_find; + } + } else { + /* + * We don't have the data in the cache. If we've got + * glue from the zone, use it. + */ + if (dns_rdataset_isassociated(&zrdataset)) { + dns_rdataset_clone(&zrdataset, rdataset); + if (sigrdataset != NULL && + dns_rdataset_isassociated(&zsigrdataset)) + dns_rdataset_clone(&zsigrdataset, + sigrdataset); + result = ISC_R_SUCCESS; + goto cleanup; + } + } + /* + * We don't know the answer. + */ + result = ISC_R_NOTFOUND; + } else if (result == DNS_R_GLUE) { + if (USECACHE(client) && RECURSIONOK(client)) { + /* + * We found an answer, but the cache may be better. + * Remember what we've got and go look in the cache. + */ + is_zone = ISC_FALSE; + version = NULL; + dns_rdataset_clone(rdataset, &zrdataset); + dns_rdataset_disassociate(rdataset); + if (sigrdataset != NULL && + dns_rdataset_isassociated(sigrdataset)) + { + dns_rdataset_clone(sigrdataset, &zsigrdataset); + dns_rdataset_disassociate(sigrdataset); + } + dns_db_detach(&db); + dns_db_attach(client->view->cachedb, &db); + goto db_find; + } + /* + * Otherwise, the glue is the best answer. + */ + result = ISC_R_SUCCESS; + } else if (result != ISC_R_SUCCESS) { + if (dns_rdataset_isassociated(rdataset)) + dns_rdataset_disassociate(rdataset); + if (sigrdataset != NULL && + dns_rdataset_isassociated(sigrdataset)) + dns_rdataset_disassociate(sigrdataset); + result = ISC_R_NOTFOUND; + } + /* + * If we get here, the result is ISC_R_SUCCESS, and we found the + * answer we were looking for in the zone. + */ + + cleanup: + if (dns_rdataset_isassociated(&zrdataset)) { + dns_rdataset_disassociate(&zrdataset); + if (sigrdataset != NULL && + dns_rdataset_isassociated(&zsigrdataset)) + dns_rdataset_disassociate(&zsigrdataset); + } + if (db != NULL) + dns_db_detach(&db); + if (zone != NULL) + dns_zone_detach(&zone); + + 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, *a6rdataset, *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; + a6rdataset = 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, 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, &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, + 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); + 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 poision 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, A6, 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_a6, 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_a6, &mname)) { + if (mname != NULL) { + query_releasename(client, &fname); + fname = mname; + } else + need_addname = ISC_TRUE; + a6rdataset = rdataset; + 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_a || type == dns_rdatatype_aaaa) { + /* + * RFC 2535 section 3.5 says that when A or AAAA records are + * retrieved as additional data, any KEY RRs for the owner name + * should be added to the additional data section. Note: we + * do NOT include A6 in the list of types with such treatment + * in additional data because we'd have to do it for each A6 + * in the A6 chain. + * + * XXXRTH We should lower the priority here. Alternatively, + * we could raise the priority of glue records. + */ + eresult = query_addadditional(client, name, dns_rdatatype_key); + } else 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); + } + + /* + * If we added an A6 rdataset, we should also add everything we + * know about the A6 chains. We wait until now to do this so that + * they'll come after any additional data added above. + */ + if (a6rdataset != NULL) { + dns_a6_reset(&client->query.a6ctx); + dns_a6_foreach(&client->query.a6ctx, a6rdataset, client->now); + } + + 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 void +query_adda6rrset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset) +{ + ns_client_t *client = arg; + dns_rdataset_t *crdataset, *csigrdataset; + isc_buffer_t b, *dbuf; + dns_name_t *fname, *mname; + + /* + * Add an rrset to the additional data section. + */ + + REQUIRE(NS_CLIENT_VALID(client)); + REQUIRE(rdataset->type == dns_rdatatype_a6); + + /* + * Get some resources... + */ + fname = NULL; + crdataset = NULL; + csigrdataset = NULL; + dbuf = query_getnamebuf(client); + if (dbuf == NULL) + goto cleanup; + fname = query_newname(client, dbuf, &b); + crdataset = query_newrdataset(client); + if (fname == NULL || crdataset == NULL) + goto cleanup; + if (sigrdataset != NULL) { + csigrdataset = query_newrdataset(client); + if (csigrdataset == NULL) + goto cleanup; + } + + if (dns_name_copy(name, fname, NULL) != ISC_R_SUCCESS) + goto cleanup; + dns_rdataset_clone(rdataset, crdataset); + if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) + dns_rdataset_clone(sigrdataset, csigrdataset); + + mname = NULL; + if (query_isduplicate(client, fname, crdataset->type, &mname)) + goto cleanup; + if (mname != NULL) { + query_releasename(client, &fname); + fname = mname; + } else { + query_keepname(client, fname, dbuf); + dns_message_addname(client->message, fname, + DNS_SECTION_ADDITIONAL); + } + + ISC_LIST_APPEND(fname->list, crdataset, link); + crdataset = NULL; + /* + * 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(csigrdataset)) { + ISC_LIST_APPEND(fname->list, csigrdataset, link); + csigrdataset = NULL; + } + + fname = NULL; + + /* + * In spite of RFC 2535 section 3.5, we don't currently try to add + * KEY RRs for the A6 records. It's just too much work. + */ + + cleanup: + query_putrdataset(client, &crdataset); + if (sigrdataset != NULL) + query_putrdataset(client, &csigrdataset); + if (fname != NULL) + query_releasename(client, &fname); +} + +static inline void +query_addrdataset(ns_client_t *client, dns_name_t *fname, + dns_rdataset_t *rdataset) +{ + dns_rdatatype_t type = rdataset->type; + + /* + * 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 (NOADDITIONAL(client)) + return; + + /* + * Add additional data. + * + * We don't care if dns_a6_foreach or dns_rdataset_additionaldata() + * fail. + */ + if (type == dns_rdatatype_a6) { + dns_a6_reset(&client->query.a6ctx); + (void)dns_a6_foreach(&client->query.a6ctx, rdataset, + client->now); + } else + (void)dns_rdataset_additionaldata(rdataset, + query_addadditional, client); + /* + * RFC 2535 section 3.5 says that when NS, SOA, A, or AAAA records + * are retrieved, any KEY RRs for the owner name should be added + * to the additional data section. We treat A6 records the same way. + * + * We don't care if query_addadditional() fails. + */ + if (type == dns_rdatatype_ns || type == dns_rdatatype_soa || + type == dns_rdatatype_a || type == dns_rdatatype_aaaa || + type == dns_rdatatype_a6) { + /* + * XXXRTH We should lower the priority here. Alternatively, + * we could raise the priority of glue records. + */ + (void)query_addadditional(client, fname, dns_rdatatype_key); + } + 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); + } + + /* + * 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, isc_boolean_t zero_ttl) { + 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_addsoa"); + /* + * 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) + 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_find(db, name, NULL, 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); + dns_rdata_tostruct(&rdata, &soa, NULL); + + 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_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. + */ + 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_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_ttl_t ttl, 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 = ttl; + + 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); + dns_rdatalist_tordataset(rdatalist, rdataset); + + 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); +} + +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, 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; + if (WANTDNSSEC(client)) { + 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; + } + + if ((client->query.dboptions & DNS_DBFIND_PENDINGOK) == 0 && + (rdataset->trust == dns_trust_pending || + (sigrdataset != NULL && sigrdataset->trust == dns_trust_pending))) + goto cleanup; + + 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_resume(isc_task_t *task, isc_event_t *event) { + dns_fetchevent_t *devent = (dns_fetchevent_t *)event; + ns_client_t *client; + isc_boolean_t fetch_cancelled, client_shuttingdown; + + /* + * 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)); + + if (devent->fetch != NULL) { + /* + * This is the fetch we've been waiting for. + */ + INSIST(devent->fetch == client->query.fetch); + client->query.fetch = NULL; + fetch_cancelled = ISC_FALSE; + /* + * Update client->now. + */ + isc_stdtime_get(&client->now); + } else { + /* + * This is a fetch completion event for a cancelled fetch. + * Clean up and don't resume the find. + */ + fetch_cancelled = ISC_TRUE; + } + INSIST(client->query.fetch == NULL); + + client->query.attributes &= ~NS_QUERYATTR_RECURSING; + dns_resolver_destroyfetch(&devent->fetch); + + /* + * 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_cancelled || 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); + query_next(client, ISC_R_CANCELED); + /* + * This may destroy the client. + */ + ns_client_detach(&client); + } else { + query_find(client, devent, 0); + } +} + +static isc_result_t +query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qdomain, + dns_rdataset_t *nameservers) +{ + isc_result_t result; + dns_rdataset_t *rdataset, *sigrdataset; + + inc_stats(client, dns_statscounter_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_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, + "no more recursive clients: %s", + isc_result_totext(result)); + return (result); + } + } + + /* + * 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); + result = dns_resolver_createfetch(client->view->resolver, + client->query.qname, + qtype, qdomain, nameservers, + NULL, 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); +} + +static inline isc_result_t +query_findparentkey(ns_client_t *client, dns_name_t *name, + dns_zone_t **zonep, dns_db_t **dbp, + dns_dbversion_t **versionp, dns_dbnode_t **nodep, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) +{ + dns_db_t *pdb; + dns_dbnode_t *pnode; + dns_dbversion_t *pversion; + dns_rdataset_t prdataset, psigrdataset; + dns_rdataset_t *psigrdatasetp; + isc_result_t result; + dns_zone_t *pzone; + isc_boolean_t is_zone; + dns_fixedname_t pfoundname; + + /* + * 'name' is at a zone cut. Try to find a KEY for 'name' in + * the deepest ancestor zone of 'name' (if any). If it exists, + * update *zonep, *dbp, *nodep, rdataset, and sigrdataset and + * return ISC_R_SUCCESS. If not, leave them alone and return a + * non-success status. + */ + + pzone = NULL; + pdb = NULL; + pnode = NULL; + pversion = NULL; + dns_rdataset_init(&prdataset); + if (sigrdataset != NULL) + dns_rdataset_init(&psigrdataset); + is_zone = ISC_FALSE; + dns_fixedname_init(&pfoundname); + + result = query_getdb(client, name, DNS_GETDB_NOEXACT, + &pzone, &pdb, &pversion, &is_zone); + if (result != ISC_R_SUCCESS) + goto cleanup; + if (!is_zone) { + result = ISC_R_FAILURE; + goto cleanup; + } + + if (sigrdataset != NULL) + psigrdatasetp = &psigrdataset; + else + psigrdatasetp = NULL; + result = dns_db_find(pdb, name, pversion, dns_rdatatype_key, + client->query.dboptions, + client->now, &pnode, + dns_fixedname_name(&pfoundname), + &prdataset, psigrdatasetp); + if (result == ISC_R_SUCCESS) { + if (dns_rdataset_isassociated(rdataset)) + dns_rdataset_disassociate(rdataset); + dns_rdataset_clone(&prdataset, rdataset); + if (sigrdataset != NULL) { + if (dns_rdataset_isassociated(sigrdataset)) + dns_rdataset_disassociate(sigrdataset); + if (dns_rdataset_isassociated(&psigrdataset)) + dns_rdataset_clone(&psigrdataset, sigrdataset); + } + if (*nodep != NULL) + dns_db_detachnode(*dbp, nodep); + *nodep = pnode; + pnode = NULL; + *versionp = pversion; + if (*dbp != NULL) + dns_db_detach(dbp); + *dbp = pdb; + pdb = NULL; + if (*zonep != NULL) + dns_zone_detach(zonep); + *zonep = pzone; + pzone = NULL; + } + + cleanup: + if (dns_rdataset_isassociated(&prdataset)) + dns_rdataset_disassociate(&prdataset); + if (sigrdataset != NULL && dns_rdataset_isassociated(&psigrdataset)) + dns_rdataset_disassociate(&psigrdataset); + if (pnode != NULL) + dns_db_detachnode(pdb, &pnode); + if (pdb != NULL) + dns_db_detach(&pdb); + if (pzone != NULL) + dns_zone_detach(&pzone); + + return (result); +} + +#define MAX_RESTARTS 16 + +#define QUERY_ERROR(r) \ +do { \ + eresult = r; \ + want_restart = ISC_FALSE; \ +} 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(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(dns_rdata_t *rdata, 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(dns_rdata_t *rdata, 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; + 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); +} + +/* + * 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 void +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; + unsigned int n, nlabels, nbits; + dns_namereln_t namereln; + int order; + isc_buffer_t *dbuf; + isc_buffer_t b; + isc_result_t result, eresult; + dns_fixedname_t fixed; + dns_dbversion_t *version; + dns_zone_t *zone; + dns_rdata_cname_t cname; + dns_rdata_dname_t dname; + isc_boolean_t empty_wild; + + 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; + empty_wild = ISC_FALSE; + + if (event != NULL) { + /* + * We're returning from recursion. Restore the query context + * and resume. + */ + + want_restart = ISC_FALSE; + authoritative = ISC_FALSE; + is_zone = ISC_FALSE; + + qtype = event->qtype; + if (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; + + goto resume; + } + + /* + * Not returning from recursion. + */ + + /* + * If it's a SIG query, we'll iterate the node. + */ + if (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; + + /* + * First we must find the right database. + */ + result = query_getdb(client, client->query.qname, 0, &zone, &db, + &version, &is_zone); + if (result != ISC_R_SUCCESS) { + if (result == DNS_R_REFUSED) + 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) { + dns_zone_attach(zone, &client->query.authzone); + 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); + + /* + * We interrupt our normal query processing to bring you this special + * case... + * + * RFC 2535 (DNSSEC), section 2.3.4, discusses various special + * cases that can occur at delegation points. + * + * One of these cases is that the NULL KEY for an unsecure zone + * may occur in the delegating zone instead of in the delegated zone. + * If we're authoritative for both zones, we need to look for the + * key in the delegator if we didn't find it in the delegatee. If + * we didn't do this, a client doing DNSSEC validation could fail + * because it couldn't get the NULL KEY. + */ + if (type == dns_rdatatype_key && + is_zone && + result == DNS_R_NXRRSET && + !dns_db_issecure(db) && + dns_name_equal(client->query.qname, dns_db_origin(db))) { + /* + * We're looking for a KEY at the top of an unsecure zone, + * and we didn't find it. + */ + result = query_findparentkey(client, client->query.qname, + &zone, &db, &version, &node, + rdataset, sigrdataset); + if (result == ISC_R_SUCCESS) { + /* + * We found the parent KEY. + * + * zone, db, version, node, rdataset, and sigrdataset + * have all been updated to refer to the parent's + * data. We will resume query processing as if + * we had looked for the KEY in the parent zone in + * the first place. + * + * We need to set fname correctly. We do this here + * instead of in query_findparentkey() because + * dns_name_copy() can fail (though it shouldn't + * ever do so since we should have enough space). + */ + result = dns_name_copy(client->query.qname, + fname, NULL); + if (result != ISC_R_SUCCESS) { + QUERY_ERROR(DNS_R_SERVFAIL); + goto cleanup; + } + } else { + /* + * We couldn't find the KEY in a parent zone. + * Continue with processing of the original + * results of dns_db_find(). + */ + result = DNS_R_NXRRSET; + } + } + + 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); + if (result == ISC_R_SUCCESS) + client->query.attributes |= + NS_QUERYATTR_RECURSING; + 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) { + /* + * 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; + } 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 (type == dns_rdatatype_key) + result = query_recurse(client, qtype, + NULL, NULL); + else + result = query_recurse(client, qtype, + fname, rdataset); + if (result == ISC_R_SUCCESS) + client->query.attributes |= + NS_QUERYATTR_RECURSING; + 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; + } + } + 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 NXT 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, ISC_FALSE); + if (result != ISC_R_SUCCESS) { + QUERY_ERROR(result); + goto cleanup; + } + /* + * Add NXT record if we found one. + */ + if (dns_rdataset_isassociated(rdataset)) { + if (WANTDNSSEC(client)) + query_addrrset(client, &fname, &rdataset, + &sigrdataset, + NULL, DNS_SECTION_AUTHORITY); + } + 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 NXT 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 a arbitary name with a stub + * resolver and not have it cached. + */ + if (qtype == dns_rdatatype_soa) + result = query_addsoa(client, db, ISC_TRUE); + else + result = query_addsoa(client, db, ISC_FALSE); + if (result != ISC_R_SUCCESS) { + QUERY_ERROR(result); + goto cleanup; + } + /* + * Add NXT record if we found one. + */ + if (dns_rdataset_isassociated(rdataset)) { + if (WANTDNSSEC(client)) + query_addrrset(client, &fname, &rdataset, + &sigrdataset, + NULL, DNS_SECTION_AUTHORITY); + } + /* + * 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; + /* + * 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; + 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; + /* + * 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); + query_maybeputqname(client); + client->query.qname = tname; + want_restart = ISC_TRUE; + 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, &nbits); + 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; + 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); + result = dns_name_split(client->query.qname, nlabels, nbits, + prefix, NULL); + if (result != ISC_R_SUCCESS) { + dns_message_puttempname(client->message, &tname); + goto cleanup; + } + 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) { + /* + * RFC 2672, 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); + query_addcnamelike(client, client->query.qname, fname, + 0, &tname, dns_rdatatype_cname); + if (tname != NULL) + dns_message_puttempname(client->message, &tname); + /* + * Switch to the new qname and restart. + */ + query_maybeputqname(client); + client->query.qname = fname; + fname = NULL; + want_restart = ISC_TRUE; + goto addauth; + default: + /* + * Something has gone wrong. + */ + QUERY_ERROR(DNS_R_SERVFAIL); + goto cleanup; + } + + 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_sig && + 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. + */ + /* + * We were searching for SIG records in + * a nonsecure zone. Send a "no error, + * no data" response. + */ + /* + * Add SOA. + */ + result = query_addsoa(client, db, 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; + query_addrrset(client, &fname, &rdataset, sigrdatasetp, dbuf, + DNS_SECTION_ANSWER); + /* + * 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)))) + query_addns(client, db); + } else if (qtype != dns_rdatatype_ns) { + if (fname != NULL) + query_releasename(client, &fname); + query_addbestns(client); + } + } + + 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 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. + */ + query_error(client, eresult); + 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 (client->message->rcode == dns_rcode_nxdomain && + client->view->auth_nxdomain == ISC_TRUE) + client->message->flags |= DNS_MESSAGEFLAG_AA; + + query_send(client); + ns_client_detach(&client); + } + CTRACE("query_find: done"); +} + +static inline void +log_query(ns_client_t *client) { + 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", namebuf, classname, typename); +} + +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; + + CTRACE("ns_query_start"); + + /* + * Ensure that appropriate cleanups occur. + */ + client->next = query_next_callback; + + if ((message->flags & DNS_MESSAGEFLAG_RD) != 0) + client->query.attributes |= NS_QUERYATTR_WANTRECURSION; + +#ifdef ISC_RFC2535 + if ((client->extflags & DNS_MESSAGEEXTFLAG_DO) != 0 || + (message->flags & DNS_MESSAGEFLAG_AD) != 0) + client->query.attributes |= NS_QUERYATTR_WANTDNSSEC; +#endif + + 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); + 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); + } else + query_error(client, result); + return; + } + + if (ns_g_server->log_queries) + log_query(client); + + /* + * Check for multiple question queries, since edns1 is dead. + */ + if (message->counts[DNS_SECTION_QUESTION] > 1) { + query_error(client, DNS_R_FORMERR); + return; + } + + /* + * Check for meta-queries like IXFR and AXFR. + */ + rdataset = ISC_LIST_HEAD(client->query.qname->list); + INSIST(rdataset != NULL); + qtype = rdataset->type; + 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); + 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); + return; + default: /* TSIG, etc. */ + query_error(client, DNS_R_FORMERR); + return; + } + } + + /* + * 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. + */ + if (message->flags & DNS_MESSAGEFLAG_CD || + qtype == dns_rdatatype_sig) + { + client->query.dboptions |= DNS_DBFIND_PENDINGOK; + client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE; + } + + /* + * 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)) + message->flags |= DNS_MESSAGEFLAG_AD; + + /* + * Synthesize IPv6 responses if appropriate. + */ + if (RECURSIONOK(client) && + (qtype == dns_rdatatype_aaaa || qtype == dns_rdatatype_ptr) && + client->message->rdclass == dns_rdataclass_in && + ns_client_checkacl(client, "v6 synthesis", + client->view->v6synthesisacl, + ISC_FALSE, ISC_LOG_DEBUG(9)) == ISC_R_SUCCESS) + { + if (qtype == dns_rdatatype_aaaa) { + qclient = NULL; + ns_client_attach(client, &qclient); + synth_fwd_start(qclient); + return; + } else { + INSIST(qtype == dns_rdatatype_ptr); + /* Must be 32 nibbles + "ip6" + "int" + root */ + if (dns_name_countlabels(client->query.qname) == 32 + 3 && + dns_name_issubdomain(client->query.qname, &ip6int_name)) { + qclient = NULL; + ns_client_attach(client, &qclient); + synth_rev_start(qclient); + return; + } + } + } + + qclient = NULL; + ns_client_attach(client, &qclient); + query_find(qclient, NULL, qtype); +} + +/* + * Generate a synthetic IPv6 forward mapping response for the current + * query of 'client'. + */ +static void +synth_fwd_start(ns_client_t *client) { + ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY, + ISC_LOG_DEBUG(5), "generating synthetic AAAA response"); + + synth_fwd_startfind(client); +} + +/* + * Start an ADB find to get addresses, or more addresses, for + * a synthetic IPv6 forward mapping response. + */ +static void +synth_fwd_startfind(ns_client_t *client) { + dns_adbfind_t *find = NULL; + isc_result_t result; + dns_fixedname_t target_fixed; + dns_name_t *target; + + dns_fixedname_init(&target_fixed); + target = dns_fixedname_name(&target_fixed); + + find_again: + result = dns_adb_createfind(client->view->adb, client->task, + synth_fwd_finddone, client, client->query.qname, + dns_rootname, + DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_RETURNLAME | + DNS_ADBFIND_INET6, client->now, + target, 0, &find); + + ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY, + ISC_LOG_DEBUG(5), "find returned %s", + isc_result_totext(result)); + + if (result == DNS_R_ALIAS) { + dns_name_t *ptarget = NULL; + dns_name_t *tname = NULL; + isc_buffer_t *dbuf; + isc_buffer_t b; + + /* + * Make a persistent copy of the 'target' name data in 'ptarget'; + * it will become the new query name. + */ + dbuf = query_getnamebuf(client); + if (dbuf == NULL) + goto fail; + ptarget = query_newname(client, dbuf, &b); + if (ptarget == NULL) + goto fail; + dns_name_copy(target, ptarget, NULL); + + dns_adb_destroyfind(&find); + + /* + * Get another temporary name 'tname' for insertion into the + * response message. + */ + result = dns_message_gettempname(client->message, &tname); + if (result != ISC_R_SUCCESS) + goto fail; + dns_name_init(tname, NULL); + result = query_addcnamelike(client, client->query.qname, + ptarget, 0 /* XXX ttl */, &tname, + dns_rdatatype_cname); + if (tname != NULL) + dns_message_puttempname(client->message, &tname); + if (result != ISC_R_SUCCESS) + goto fail; + + query_maybeputqname(client); + client->query.qname = ptarget; + query_keepname(client, ptarget, dbuf); + ptarget = NULL; + if (client->query.restarts < MAX_RESTARTS) { + client->query.restarts++; + goto find_again; + } else { + /* + * Probably a CNAME loop. Reply with partial + * CNAME chain. + */ + result = ISC_R_SUCCESS; + goto done; + } + } else if (result != ISC_R_SUCCESS) { + if (find != NULL) + dns_adb_destroyfind(&find); + goto fail; + } + + if ((find->options & DNS_ADBFIND_WANTEVENT) != 0) { + ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY, + ISC_LOG_DEBUG(5), "find will send event"); + } else { + synth_fwd_respond(client, find); + dns_adb_destroyfind(&find); + } + return; + + fail: + result = DNS_R_SERVFAIL; + done: + synth_finish(client, result); +} + +/* + * Handle an ADB finddone event generated as part of synthetic IPv6 + * forward mapping processing. + */ +static void +synth_fwd_finddone(isc_task_t *task, isc_event_t *ev) { + ns_client_t *client = ev->ev_arg; + dns_adbfind_t *find = ev->ev_sender; + isc_eventtype_t evtype = ev->ev_type; + + UNUSED(task); + + ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY, + ISC_LOG_DEBUG(5), "got find event"); + + if (evtype == DNS_EVENT_ADBNOMOREADDRESSES) + synth_fwd_respond(client, find); + else if (evtype == DNS_EVENT_ADBMOREADDRESSES) + synth_fwd_startfind(client); + else + synth_finish(client, DNS_R_SERVFAIL); + + isc_event_free(&ev); + dns_adb_destroyfind(&find); + +} + +/* + * Generate a synthetic IPv6 forward mapping response based on + * a completed ADB lookup. + */ +static void +synth_fwd_respond(ns_client_t *client, dns_adbfind_t *find) { + dns_adbaddrinfo_t *ai; + dns_name_t *tname = NULL; + dns_rdataset_t *rdataset = NULL; + dns_rdatalist_t *rdatalist = NULL; + isc_result_t result; + + result = dns_message_gettempname(client->message, &tname); + if (result != ISC_R_SUCCESS) + goto cleanup; + dns_name_init(tname, NULL); + + result = dns_message_gettemprdatalist(client->message, &rdatalist); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = dns_message_gettemprdataset(client->message, &rdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + dns_rdataset_init(rdataset); + + ISC_LIST_INIT(rdatalist->rdata); + + rdatalist->type = dns_rdatatype_aaaa; + rdatalist->covers = 0; + rdatalist->rdclass = client->message->rdclass; + rdatalist->ttl = 0; + + dns_name_clone(client->query.qname, tname); + + for (ai = ISC_LIST_HEAD(find->list); + ai != NULL; + ai = ISC_LIST_NEXT(ai, publink)) { + dns_rdata_t *rdata = NULL; + + struct sockaddr_in6 *sin6 = &ai->sockaddr.type.sin6; + /* + * Could it be useful to return IPv4 addresses as A records? + */ + if (sin6->sin6_family != AF_INET6) + continue; + + result = dns_message_gettemprdata(client->message, &rdata); + if (result != ISC_R_SUCCESS) + goto cleanup; + + rdata->data = (unsigned char *) &sin6->sin6_addr; + rdata->length = 16; + rdata->rdclass = client->message->rdclass; + rdata->type = dns_rdatatype_aaaa; + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + } + + dns_rdatalist_tordataset(rdatalist, rdataset); + + query_addrrset(client, &tname, &rdataset, NULL, NULL, + DNS_SECTION_ANSWER); + + cleanup: + if (tname != NULL) + dns_message_puttempname(client->message, &tname); + + if (rdataset != NULL) { + if (dns_rdataset_isassociated(rdataset)) + dns_rdataset_disassociate(rdataset); + dns_message_puttemprdataset(client->message, &rdataset); + } + + synth_finish(client, result); +} + +/* + * Finish synthetic IPv6 forward mapping processing. + */ +static void +synth_finish(ns_client_t *client, isc_result_t result) { + if (result == ISC_R_SUCCESS) + query_send(client); + else + query_error(client, result); + ns_client_detach(&client); +} + +static signed char ascii2hex[256] = { + -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, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -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, 10, 11, 12, 13, 14, 15, -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, -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 +}; + +/* + * Convert label 'i' of 'name' into its hexadecimal value, storing it + * in '*hexp'. If the label is not a valid hex nibble, return ISC_R_FAILURE. + */ +static isc_result_t +label2hex(dns_name_t *name, int i, int *hexp) { + isc_region_t label; + int hexval; + dns_name_getlabel(name, i, &label); + if (label.length != 2 || label.base[0] != '\001') + return (ISC_R_FAILURE); + hexval = ascii2hex[label.base[1]]; + if (hexval == -1) + return (ISC_R_FAILURE); + *hexp = hexval; + return (ISC_R_SUCCESS); +} + +/* + * Convert the ip6.int name 'name' into the corresponding IPv6 address + * in 'na'. + */ +static isc_result_t +nibbles2netaddr(dns_name_t *name, isc_netaddr_t *na) { + isc_result_t result; + struct in6_addr ina6; + unsigned char *addrdata = (unsigned char *) &ina6; + int i; + + for (i = 0; i < 16; i++) { + int hex0, hex1; + result = label2hex(name, 2 * i, &hex0); + if (result != ISC_R_SUCCESS) + return (result); + result = label2hex(name, 2 * i + 1, &hex1); + if (result != ISC_R_SUCCESS) + return (result); + addrdata[15-i] = (hex1 << 4) | hex0; + } + isc_netaddr_fromin6(na, &ina6); + return (ISC_R_SUCCESS); +} + +/* + * Generate a synthetic IPv6 reverse mapping response for the current + * query of 'client'. + */ +static void +synth_rev_start(ns_client_t *client) { + isc_result_t result; + dns_byaddr_t *byaddr_dummy = NULL; + + ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY, + ISC_LOG_DEBUG(5), "generating synthetic PTR response"); + + result = nibbles2netaddr(client->query.qname, &client->query.synth.na); + if (result != ISC_R_SUCCESS) { + result = DNS_R_NXDOMAIN; + goto cleanup; + } + + /* Try IP6.ARPA first. */ + result = dns_byaddr_create(client->mctx, + &client->query.synth.na, + client->view, + DNS_BYADDROPT_IPV6NIBBLE, + client->task, + synth_rev_byaddrdone_arpa, + client, &byaddr_dummy); + if (result == ISC_R_SUCCESS) + return; /* Wait for completion event. */ + cleanup: + synth_finish(client, result); +} + +static void +synth_rev_byaddrdone_arpa(isc_task_t *task, isc_event_t *event) { + isc_result_t result; + dns_byaddrevent_t *bevent = (dns_byaddrevent_t *)event; + ns_client_t *client = event->ev_arg; + dns_byaddr_t *byaddr = event->ev_sender; + dns_byaddr_t *byaddr_dummy = NULL; + + UNUSED(task); + + if (bevent->result == ISC_R_SUCCESS) { + synth_rev_respond(client, bevent); + } else { + /* Try IP6.INT next. */ + result = dns_byaddr_create(client->mctx, + &client->query.synth.na, + client->view, + DNS_BYADDROPT_IPV6NIBBLE| + DNS_BYADDROPT_IPV6INT, + client->task, + synth_rev_byaddrdone_int, + client, &byaddr_dummy); + if (result != ISC_R_SUCCESS) + synth_finish(client, result); + } + dns_byaddr_destroy(&byaddr); + isc_event_free(&event); +} + +static void +synth_rev_byaddrdone_int(isc_task_t *task, isc_event_t *event) { + dns_byaddrevent_t *bevent = (dns_byaddrevent_t *)event; + ns_client_t *client = event->ev_arg; + dns_byaddr_t *byaddr = event->ev_sender; + + UNUSED(task); + + if (bevent->result == ISC_R_SUCCESS) { + synth_rev_respond(client, bevent); + } else if (bevent->result == DNS_R_NCACHENXDOMAIN || + bevent->result == DNS_R_NCACHENXRRSET || + bevent->result == DNS_R_NXDOMAIN || + bevent->result == DNS_R_NXRRSET) { + /* + * We could give a NOERROR/NODATA response instead + * in some cases, but since there may be any combination + * of NXDOMAIN and NXRRSET results from the IP6.INT + * and IP6.ARPA lookups, it could still be wrong with + * respect to one or the other. + */ + synth_finish(client, DNS_R_NXDOMAIN); + } else { + synth_finish(client, bevent->result); + } + isc_event_free(&event); + dns_byaddr_destroy(&byaddr); +} + +static void +synth_rev_respond(ns_client_t *client, dns_byaddrevent_t *bevent) { + isc_result_t result = ISC_R_SUCCESS; + dns_name_t *name; + + for (name = ISC_LIST_HEAD(bevent->names); + name != NULL; + name = ISC_LIST_NEXT(name, link)) + { + dns_name_t *tname = NULL; + + /* + * Get a temporary name 'tname' for insertion into the + * response message. + */ + result = dns_message_gettempname(client->message, &tname); + if (result != ISC_R_SUCCESS) + goto fail; + dns_name_init(tname, NULL); + + result = query_addcnamelike(client, client->query.qname, + name, 0 /* XXX ttl */, + &tname, dns_rdatatype_ptr); + if (tname != NULL) + dns_message_puttempname(client->message, &tname); + if (result != ISC_R_SUCCESS) + goto fail; + } + fail: + synth_finish(client, result); +} diff --git a/contrib/bind-9.2.4rc7/bin/named/server.c b/contrib/bind-9.2.4rc7/bin/named/server.c new file mode 100644 index 0000000000..0afa93a4fe --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/server.c @@ -0,0 +1,3132 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2003 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: server.c,v 1.339.2.29 2004/05/14 01:04:46 marka Exp $ */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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 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; +}; + +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(cfg_obj_t *listener, cfg_obj_t *config, + ns_aclconfctx_t *actx, + isc_mem_t *mctx, ns_listenelt_t **target); +static isc_result_t +ns_listenlist_fromconfig(cfg_obj_t *listenlist, cfg_obj_t *config, + ns_aclconfctx_t *actx, + isc_mem_t *mctx, ns_listenlist_t **target); + +static isc_result_t +configure_forward(cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, + cfg_obj_t *forwarders, cfg_obj_t *forwardtype); + +static isc_result_t +configure_zone(cfg_obj_t *config, cfg_obj_t *zconfig, cfg_obj_t *vconfig, + isc_mem_t *mctx, dns_view_t *view, + ns_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 by + * calling 'getvcacl' (for per-view configuration) and maybe 'getscacl' + * (for a global default). + */ +static isc_result_t +configure_view_acl(cfg_obj_t *vconfig, cfg_obj_t *config, + const char *aclname, ns_aclconfctx_t *actx, + isc_mem_t *mctx, dns_acl_t **aclp) +{ + isc_result_t result; + cfg_obj_t *maps[3]; + 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) { + cfg_obj_t *options = NULL; + cfg_map_get(config, "options", &options); + if (options != NULL) + maps[i++] = options; + } + maps[i] = NULL; + + result = ns_config_get(maps, aclname, &aclobj); + if (aclobj == NULL) + /* + * No value available. *aclp == NULL. + */ + return (ISC_R_SUCCESS); + + result = ns_acl_fromconfig(aclobj, config, actx, mctx, aclp); + + return (result); +} + +#ifdef ISC_RFC2535 +static isc_result_t +configure_view_dnsseckey(cfg_obj_t *vconfig, cfg_obj_t *key, + dns_keytable_t *keytable, isc_mem_t *mctx) +{ + dns_rdataclass_t viewclass; + dns_rdata_key_t keystruct; + isc_uint32_t flags, proto, alg; + 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 { + 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_key; + /* + * 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; + + 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); +} +#endif + +/* + * 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(cfg_obj_t *vconfig, cfg_obj_t *config, + isc_mem_t *mctx, dns_keytable_t **target) +{ + isc_result_t result; +#ifdef ISC_RFC2535 + cfg_obj_t *keys = NULL; + cfg_obj_t *voptions = NULL; + cfg_listelt_t *element, *element2; + cfg_obj_t *keylist; + cfg_obj_t *key; +#endif + dns_keytable_t *keytable = NULL; + + CHECK(dns_keytable_create(mctx, &keytable)); + +#ifndef ISC_RFC2535 + UNUSED(vconfig); + UNUSED(config); +#else + 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)); + } + } +#endif + dns_keytable_detach(target); + *target = keytable; /* Transfer ownership. */ + keytable = NULL; + 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(cfg_obj_t **maps, + int af, dns_dispatch_t **dispatchp) +{ + isc_result_t result; + dns_dispatch_t *disp; + isc_sockaddr_t sa; + unsigned int attrs, attrmask; + cfg_obj_t *obj = NULL; + + /* + * 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; + } + 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, + 1000, 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_peer(cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) { + isc_sockaddr_t *sa; + isc_netaddr_t na; + dns_peer_t *peer; + cfg_obj_t *obj; + char *str; + isc_result_t result; + + sa = cfg_obj_assockaddr(cfg_map_getname(cpeer)); + isc_netaddr_fromsockaddr(&na, sa); + + peer = NULL; + result = dns_peer_new(mctx, &na, &peer); + if (result != ISC_R_SUCCESS) + return (result); + + obj = NULL; + (void)cfg_map_get(cpeer, "bogus", &obj); + if (obj != NULL) + dns_peer_setbogus(peer, cfg_obj_asboolean(obj)); + + obj = NULL; + (void)cfg_map_get(cpeer, "provide-ixfr", &obj); + if (obj != NULL) + dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)); + + obj = NULL; + (void)cfg_map_get(cpeer, "request-ixfr", &obj); + if (obj != NULL) + dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)); + + obj = NULL; + (void)cfg_map_get(cpeer, "edns", &obj); + if (obj != NULL) + dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj)); + + obj = NULL; + (void)cfg_map_get(cpeer, "transfers", &obj); + if (obj != NULL) + 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) + dns_peer_settransferformat(peer, dns_many_answers); + else if (strcasecmp(str, "one-answer") == 0) + 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; + } + *peerp = peer; + return (ISC_R_SUCCESS); + + cleanup: + dns_peer_detach(&peer); + return (result); +} + +/* + * 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, cfg_obj_t *config, cfg_obj_t *vconfig, + isc_mem_t *mctx, ns_aclconfctx_t *actx) +{ + cfg_obj_t *maps[4]; + cfg_obj_t *cfgmaps[3]; + cfg_obj_t *options = NULL; + cfg_obj_t *voptions = NULL; + cfg_obj_t *forwardtype; + cfg_obj_t *forwarders; + cfg_obj_t *zonelist; + cfg_obj_t *obj; + cfg_listelt_t *element; + in_port_t port; + dns_cache_t *cache = NULL; + isc_result_t result; + isc_uint32_t max_cache_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; + char *str; + + REQUIRE(DNS_VIEW_VALID(view)); + + cmctx = NULL; + + if (config != NULL) + 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; + + + /* + * Set the view's port number for outgoing queries. + */ + CHECKM(ns_config_getport(config, &port), "port"); + dns_view_setdstport(view, port); + + /* + * 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)) + { + cfg_obj_t *zconfig = cfg_listelt_value(element); + CHECK(configure_zone(config, zconfig, vconfig, mctx, view, + actx)); + } + + /* + * 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. + * + * 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. As more view attributes become + * configurable, we will have to add code here to check + * whether they have changed in ways that could + * invalidate the cache. + */ + 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) { + 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); + dns_view_detach(&pview); + } else { + CHECK(isc_mem_create(0, 0, &cmctx)); + CHECK(dns_cache_create(cmctx, ns_g_taskmgr, ns_g_timermgr, + view->rdclass, "rbt", 0, NULL, &cache)); + } + 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) { + 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)); + CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6)); + 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, + 0, ns_g_dispatchmgr, + dispatch4, dispatch6)); + + /* + * 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); + + /* + * 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)); + + /* + * 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 requireing users to configure + * them. + */ + if (view->hints == NULL) { + dns_zone_t *rootzone = NULL; + dns_view_findzone(view, dns_rootname, &rootzone); + if (rootzone != NULL) { + dns_zone_detach(&rootzone); + } else { + 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. + */ + { + cfg_obj_t *peers = NULL; + 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)) + { + 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. */ + } + + /* + * 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; + } + + CHECK(configure_view_acl(vconfig, config, "allow-query", + actx, ns_g_mctx, &view->queryacl)); + + 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-v6-synthesis", + actx, ns_g_mctx, &view->v6synthesisacl)); + + /* + * Warning if both "recursion no;" and allow-recursion are active + * except for "allow-recursion { none; };". + */ + if (!view->recursion && view->recursionacl != NULL && + (view->recursionacl->length != 1 || + view->recursionacl->elements[0].type != dns_aclelementtype_any || + view->recursionacl->elements[0].negative != ISC_TRUE)) { + const char *forview = " for view "; + const char *viewname = view->name; + + if (!strcmp(view->name, "_bind") || + !strcmp(view->name, "_default")) { + forview = ""; + viewname = ""; + } + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_WARNING, + "both \"recursion no;\" and \"allow-recursion\" " + "active%s%s", forview, viewname); + } + + CHECK(configure_view_acl(vconfig, config, "sortlist", + actx, ns_g_mctx, &view->sortlist)); + + 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); + + /* + * For now, there is only one kind of trusted keys, the + * "security roots". + */ + CHECK(configure_view_dnsseckeys(vconfig, config, mctx, + &view->secroots)); + + 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; + + 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; + char *str; + 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); + + result = ISC_R_SUCCESS; + + cleanup: + if (dispatch4 != NULL) + dns_dispatch_detach(&dispatch4); + if (dispatch6 != NULL) + dns_dispatch_detach(&dispatch6); + if (cmctx != NULL) + isc_mem_detach(&cmctx); + + if (cache != NULL) + dns_cache_detach(&cache); + + return (result); +} + +/* + * Create the special view that handles queries under "bind. CH". + */ +static isc_result_t +create_bind_view(dns_view_t **viewp) { + isc_result_t result; + dns_view_t *view = NULL; + + REQUIRE(viewp != NULL && *viewp == NULL); + + CHECK(dns_view_create(ns_g_mctx, dns_rdataclass_ch, "_bind", &view)); + + /* Transfer ownership. */ + *viewp = view; + view = NULL; + + result = ISC_R_SUCCESS; + + cleanup: + if (view != NULL) + dns_view_detach(&view); + + return (result); +} + +/* + * Create the zone that handles queries for "version.bind. CH". The + * version string is returned either from the "version" configuration + * option or the global defaults. + */ +static isc_result_t +create_version_zone(cfg_obj_t **maps, dns_zonemgr_t *zmgr, dns_view_t *view) { + isc_result_t result; + dns_db_t *db = NULL; + dns_zone_t *zone = NULL; + dns_dbversion_t *dbver = NULL; + dns_difftuple_t *tuple = NULL; + dns_diff_t diff; + char *versiontext; + unsigned char buf[256]; + isc_region_t r; + size_t len; + dns_rdata_t rdata = DNS_RDATA_INIT; + static unsigned char origindata[] = "\007version\004bind"; + dns_name_t origin; + cfg_obj_t *obj = NULL; + dns_acl_t *acl = NULL; + + dns_diff_init(ns_g_mctx, &diff); + + dns_name_init(&origin, NULL); + r.base = origindata; + r.length = sizeof(origindata); + dns_name_fromregion(&origin, &r); + + result = ns_config_get(maps, "version", &obj); + INSIST(result == ISC_R_SUCCESS); + versiontext = cfg_obj_asstring(obj); + len = strlen(versiontext); + if (len > 255U) + len = 255; /* Silently truncate. */ + buf[0] = len; + memcpy(buf + 1, versiontext, len); + + r.base = buf; + r.length = 1 + len; + dns_rdata_fromregion(&rdata, dns_rdataclass_ch, dns_rdatatype_txt, &r); + + CHECK(dns_zone_create(&zone, ns_g_mctx)); + CHECK(dns_zone_setorigin(zone, &origin)); + dns_zone_settype(zone, dns_zone_master); + dns_zone_setclass(zone, dns_rdataclass_ch); + /* Transfers don't work so deny them. */ + CHECK(dns_acl_none(ns_g_mctx, &acl)); + dns_zone_setxfracl(zone, acl); + dns_acl_detach(&acl); + dns_zone_setview(zone, view); + + CHECK(dns_zonemgr_managezone(zmgr, zone)); + + CHECK(dns_db_create(ns_g_mctx, "rbt", &origin, dns_dbtype_zone, + dns_rdataclass_ch, 0, NULL, &db)); + + CHECK(dns_db_newversion(db, &dbver)); + + CHECK(dns_difftuple_create(ns_g_mctx, DNS_DIFFOP_ADD, &origin, + 0, &rdata, &tuple)); + dns_diff_append(&diff, &tuple); + CHECK(dns_diff_apply(&diff, db, dbver)); + + dns_db_closeversion(db, &dbver, ISC_TRUE); + + CHECK(dns_zone_replacedb(zone, db, ISC_FALSE)); + + CHECK(dns_view_addzone(view, zone)); + + result = ISC_R_SUCCESS; + + cleanup: + if (zone != NULL) + dns_zone_detach(&zone); + if (dbver != NULL) + dns_db_closeversion(db, &dbver, ISC_FALSE); + if (db != NULL) + dns_db_detach(&db); + dns_diff_clear(&diff); + + return (result); +} + +/* + * Create the special zone that handles queries for "authors.bind. CH". + * The strings returned list the BIND 9 authors. + */ +static isc_result_t +create_authors_zone(cfg_obj_t *options, dns_zonemgr_t *zmgr, dns_view_t *view) +{ + isc_result_t result; + dns_db_t *db = NULL; + dns_zone_t *zone = NULL; + dns_dbversion_t *dbver = NULL; + dns_difftuple_t *tuple; + dns_diff_t diff; + isc_region_t r; + isc_region_t cr; + dns_rdata_t rdata = DNS_RDATA_INIT; + static const char origindata[] = "\007authors\004bind"; + dns_name_t origin; + int i; + static const char *authors[] = { + "\014Mark Andrews", + "\015James Brister", + "\014Ben Cottrell", + "\015Michael Graff", + "\022Andreas Gustafsson", + "\012Bob Halley", + "\016David Lawrence", + "\013Danny Mayer", + "\013Damien Neil", + "\013Matt Nelson", + "\016Michael Sawyer", + "\020Brian Wellington", + NULL, + }; + cfg_obj_t *obj = NULL; + dns_acl_t *acl = NULL; + + /* + * If a version string is specified, disable the authors.bind zone. + */ + if (options != NULL && + cfg_map_get(options, "version", &obj) == ISC_R_SUCCESS) + return (ISC_R_SUCCESS); + + dns_diff_init(ns_g_mctx, &diff); + + dns_name_init(&origin, NULL); + DE_CONST(origindata, r.base); + r.length = sizeof(origindata); + dns_name_fromregion(&origin, &r); + + CHECK(dns_zone_create(&zone, ns_g_mctx)); + CHECK(dns_zone_setorigin(zone, &origin)); + dns_zone_settype(zone, dns_zone_master); + dns_zone_setclass(zone, dns_rdataclass_ch); + /* Transfers don't work so deny them. */ + CHECK(dns_acl_none(ns_g_mctx, &acl)); + dns_zone_setxfracl(zone, acl); + dns_acl_detach(&acl); + dns_zone_setview(zone, view); + + CHECK(dns_zonemgr_managezone(zmgr, zone)); + + CHECK(dns_db_create(ns_g_mctx, "rbt", &origin, dns_dbtype_zone, + dns_rdataclass_ch, 0, NULL, &db)); + + CHECK(dns_db_newversion(db, &dbver)); + + for (i = 0; authors[i] != NULL; i++) { + DE_CONST(authors[i], cr.base); + cr.length = strlen(authors[i]); + INSIST(cr.length == ((const unsigned char *)cr.base)[0] + 1U); + dns_rdata_fromregion(&rdata, dns_rdataclass_ch, + dns_rdatatype_txt, &cr); + tuple = NULL; + CHECK(dns_difftuple_create(ns_g_mctx, DNS_DIFFOP_ADD, &origin, + 0, &rdata, &tuple)); + dns_diff_append(&diff, &tuple); + dns_rdata_reset(&rdata); + } + + CHECK(dns_diff_apply(&diff, db, dbver)); + + dns_db_closeversion(db, &dbver, ISC_TRUE); + + CHECK(dns_zone_replacedb(zone, db, ISC_FALSE)); + + CHECK(dns_view_addzone(view, zone)); + + result = ISC_R_SUCCESS; + + cleanup: + if (zone != NULL) + dns_zone_detach(&zone); + if (dbver != NULL) + dns_db_closeversion(db, &dbver, ISC_FALSE); + if (db != NULL) + dns_db_detach(&db); + dns_diff_clear(&diff); + + 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_forward(cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, + cfg_obj_t *forwarders, cfg_obj_t *forwardtype) +{ + cfg_obj_t *portobj; + cfg_obj_t *faddresses; + 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; + + /* + * 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"); + + ISC_LIST_INIT(addresses); + + for (element = cfg_list_first(faddresses); + element != NULL; + element = cfg_list_next(element)) + { + 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 { + 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(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) { + 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(cfg_obj_t *config, cfg_obj_t *zconfig, cfg_obj_t *vconfig, + isc_mem_t *mctx, dns_view_t *view, + ns_aclconfctx_t *aclconf) +{ + dns_view_t *pview = NULL; /* Production view */ + dns_zone_t *zone = NULL; /* New or reused zone */ + dns_zone_t *dupzone = NULL; + cfg_obj_t *options = NULL; + cfg_obj_t *zoptions = NULL; + cfg_obj_t *typeobj = NULL; + cfg_obj_t *forwarders = NULL; + cfg_obj_t *forwardtype = NULL; + 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) { + 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)) { + 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! + */ + 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) { + if (! 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); + } 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); + CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); + } + + /* + * If the zone contains a 'forwarders' statement, configure + * selective forwarding. + */ + forwarders = NULL; + if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS) + { + forwardtype = NULL; + 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(cfg_obj_t **maps, const char *name, isc_quota_t *quota) +{ + cfg_obj_t *obj = NULL; + isc_result_t result; + + result = ns_config_get(maps, name, &obj); + INSIST(result == ISC_R_SUCCESS); + quota->max = 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, cfg_obj_t *obj, void *arg) { + isc_result_t result; + 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; +} + +/* + * 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 isc_result_t +setstatsfile(ns_server_t *server, const char *name) { + char *p; + + REQUIRE(name != NULL); + + p = isc_mem_strdup(server->mctx, name); + if (p == NULL) + return (ISC_R_NOMEMORY); + if (server->statsfile != NULL) + isc_mem_free(server->mctx, server->statsfile); + server->statsfile = p; + return (ISC_R_SUCCESS); +} + +static isc_result_t +setdumpfile(ns_server_t *server, const char *name) { + char *p; + + REQUIRE(name != NULL); + + p = isc_mem_strdup(server->mctx, name); + if (p == NULL) + return (ISC_R_NOMEMORY); + if (server->dumpfile != NULL) + isc_mem_free(server->mctx, server->dumpfile); + server->dumpfile = p; + return (ISC_R_SUCCESS); +} + +static void +set_limit(cfg_obj_t **maps, const char *configname, const char *description, + isc_resource_t resourceid, isc_resourcevalue_t defaultvalue) +{ + cfg_obj_t *obj = NULL; + 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(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 isc_result_t +load_configuration(const char *filename, ns_server_t *server, + isc_boolean_t first_time) +{ + isc_result_t result; + cfg_parser_t *parser = NULL; + cfg_obj_t *config; + cfg_obj_t *options; + cfg_obj_t *views; + cfg_obj_t *obj; + cfg_obj_t *maps[3]; + cfg_listelt_t *element; + dns_view_t *view = NULL; + dns_view_t *view_next; + dns_viewlist_t viewlist; + dns_viewlist_t tmpviewlist; + ns_aclconfctx_t aclconfctx; + isc_uint32_t interface_interval; + isc_uint32_t heartbeat_interval; + in_port_t listen_port; + int i; + + ns_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(cfg_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); + + /* + * 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); + + 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); + + /* + * 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"); + + /* + * Configure the interface manager according to the "listen-on" + * statement. + */ + { + 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. + */ + { + 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) { + isc_timer_reset(server->interface_timer, + isc_timertype_inactive, + NULL, NULL, ISC_TRUE); + } else if (server->interface_interval != interface_interval) { + isc_interval_t interval; + isc_interval_set(&interval, interface_interval, 0); + 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) { + isc_timer_reset(server->heartbeat_timer, + isc_timertype_inactive, + NULL, NULL, ISC_TRUE); + } else if (server->heartbeat_interval != heartbeat_interval) { + isc_interval_t interval; + isc_interval_set(&interval, heartbeat_interval, 0); + isc_timer_reset(server->heartbeat_timer, isc_timertype_ticker, + NULL, &interval, ISC_FALSE); + } + server->heartbeat_interval = heartbeat_interval; + + /* + * 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)) + { + cfg_obj_t *vconfig; + + view = NULL; + vconfig = cfg_listelt_value(element); + CHECK(create_view(vconfig, &viewlist, &view)); + INSIST(view != NULL); + CHECK(configure_view(view, config, vconfig, + ns_g_mctx, &aclconfctx)); + 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)); + dns_view_freeze(view); + dns_view_detach(&view); + } + + /* + * Create (or recreate) the internal _bind view. + */ + CHECK(create_bind_view(&view)); + CHECK(configure_view_acl(NULL, config, "allow-query", + &aclconfctx, ns_g_mctx, &view->queryacl)); + ISC_LIST_APPEND(viewlist, view, link); + CHECK(create_version_zone(maps, server->zonemgr, view)); + CHECK(create_authors_zone(options, server->zonemgr, view)); + dns_view_freeze(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)); + } + } + + /* + * Relinquish root privileges. + */ + if (first_time) + ns_os_changeuser(); + + /* + * 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 { + 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) { + cfg_obj_t *logobj = NULL; + cfg_obj_t *categories = NULL; + (void)cfg_map_get(config, "logging", &logobj); + if (logobj != NULL) + (void)cfg_map_get(logobj, "category", &categories); + if (categories != NULL) { + cfg_listelt_t *element; + for (element = cfg_list_first(categories); + element != NULL; + element = cfg_list_next(element)) + { + cfg_obj_t *catobj; + 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) + 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; + result = ns_config_get(maps, "statistics-file", &obj); + INSIST(result == ISC_R_SUCCESS); + CHECKM(setstatsfile(server, cfg_obj_asstring(obj)), "strdup"); + + obj = NULL; + result = ns_config_get(maps, "dump-file", &obj); + INSIST(result == ISC_R_SUCCESS); + CHECKM(setdumpfile(server, cfg_obj_asstring(obj)), "strdup"); + + cleanup: + ns_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); + dns_view_detach(&view); + + } + + /* 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. + */ + CHECK(dns_zonemgr_forcemaint(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; + + UNUSED(task); + + isc_event_free(&event); + + CHECKFATAL(dns_dispatchmgr_create(ns_g_mctx, ns_g_entropy, + &ns_g_dispatchmgr), + "creating dispatch manager"); + + 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(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"); + + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, + ISC_LOG_INFO, "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_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); + + 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->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->querystats = NULL; + CHECKFATAL(dns_stats_alloccounters(ns_g_mctx, &server->querystats), + "dns_stats_alloccounters"); + + server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db"); + CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, + "isc_mem_strdup"); + + 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); + + 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); + + dns_stats_freecounters(server->mctx, &server->querystats); + isc_mem_free(server->mctx, server->statsfile); + + isc_mem_free(server->mctx, server->dumpfile); + + 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, 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); + 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 void +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_ERROR, + "reloading zones failed: %s", + isc_result_totext(result)); + } + cleanup: ; +} + +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_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); + + 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) + viewtxt = "_default"; + 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); + /* Partial match? */ + if (result != ISC_R_SUCCESS && *zonep != NULL) + dns_zone_detach(zonep); + dns_view_detach(&view); + fail1: + return (result); +} + +/* + * Act on a "reload" command from the command channel. + */ +isc_result_t +ns_server_reloadcommand(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) { + reload(server); + } else { + type = dns_zone_gettype(zone); + if (type == dns_zone_slave || type == dns_zone_stub) + dns_zone_refresh(zone); + else + dns_zone_load(zone); + dns_zone_detach(&zone); + } + return (ISC_R_SUCCESS); +} + +/* + * 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 "refresh" command from the command channel. + */ +isc_result_t +ns_server_refreshcommand(ns_server_t *server, char *args) { + isc_result_t result; + dns_zone_t *zone = NULL; + + result = zone_from_args(server, args, &zone); + if (result != ISC_R_SUCCESS) + return (result); + if (zone == NULL) + return (ISC_R_UNEXPECTEDEND); + + dns_zone_refresh(zone); + dns_zone_detach(&zone); + + return (ISC_R_SUCCESS); +} + +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(cfg_obj_t *listenlist, cfg_obj_t *config, + ns_aclconfctx_t *actx, + isc_mem_t *mctx, ns_listenlist_t **target) +{ + isc_result_t result; + 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; + 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(cfg_obj_t *listener, cfg_obj_t *config, + ns_aclconfctx_t *actx, + isc_mem_t *mctx, ns_listenelt_t **target) +{ + isc_result_t result; + 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 = ns_acl_fromconfig(cfg_tuple_get(listener, "acl"), + config, actx, mctx, &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; + dns_zone_t *zone, *next; + isc_stdtime_t now; + FILE *fp = NULL; + int i; + int ncounters; + + isc_stdtime_get(&now); + + CHECKM(isc_stdio_open(server->statsfile, "a", &fp), + "could not open statistics dump file"); + + ncounters = DNS_STATS_NCOUNTERS; + fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now); + + for (i = 0; i < ncounters; i++) + fprintf(fp, "%s %" ISC_PRINT_QUADFORMAT "u\n", + dns_statscounter_names[i], + server->querystats[i]); + + 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_uint64_t *zonestats = dns_zone_getstatscounters(zone); + if (zonestats != NULL) { + char zonename[DNS_NAME_FORMATSIZE]; + dns_view_t *view; + char *viewname; + + dns_name_format(dns_zone_getorigin(zone), + zonename, sizeof(zonename)); + view = dns_zone_getview(zone); + viewname = view->name; + for (i = 0; i < ncounters; i++) { + fprintf(fp, "%s %" ISC_PRINT_QUADFORMAT + "u %s", + dns_statscounter_names[i], + zonestats[i], + zonename); + if (strcmp(viewname, "_default") != 0) + fprintf(fp, " %s", viewname); + fprintf(fp, "\n"); + } + } + } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + CHECK(result); + + fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now); + + cleanup: + if (fp != NULL) + (void)isc_stdio_close(fp); + return (result); +} + +isc_result_t +ns_server_dumpdb(ns_server_t *server) { + FILE *fp = NULL; + dns_view_t *view; + isc_result_t result; + + CHECKM(isc_stdio_open(server->dumpfile, "w", &fp), + "could not open dump file"); + + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (view->cachedb != NULL) + CHECKM(dns_view_dumpdbtostream(view, fp), + "could not dump view databases"); + } + cleanup: + if (fp != NULL) + (void)isc_stdio_close(fp); + 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); + return (ISC_R_SUCCESS); +} + +isc_result_t +ns_server_flushcache(ns_server_t *server, char *args) { + char *ptr, *viewname; + dns_view_t *view; + isc_boolean_t flushed = ISC_FALSE; + 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); + 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; + flushed = ISC_TRUE; + } + if (flushed) + result = ISC_R_SUCCESS; + else + result = ISC_R_FAILURE; + out: + 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; + + 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), + "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" + "server is up and running", + zonecount, ns_g_debuglevel, xferrunning, xferdeferred, + soaqueries, server->log_queries ? "ON" : "OFF"); + if (n >= isc_buffer_availablelength(text)) + return (ISC_R_NOSPACE); + isc_buffer_add(text, n); + return (ISC_R_SUCCESS); +} diff --git a/contrib/bind-9.2.4rc7/bin/named/sortlist.c b/contrib/bind-9.2.4rc7/bin/named/sortlist.c new file mode 100644 index 0000000000..4e8cffbcc7 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/sortlist.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 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: sortlist.c,v 1.5.2.1 2004/03/09 06:09:20 marka Exp $ */ + +#include + +#include +#include + +#include +#include + +#include +#include +#include + +ns_sortlisttype_t +ns_sortlist_setup(dns_acl_t *acl, isc_netaddr_t *clientaddr, 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 *matchelt = NULL; + dns_acl_t *inner; + + if (e->type != dns_aclelementtype_nestedacl) + goto dont_sort; + + inner = e->u.nestedacl; + + if (inner->length < 1 || inner->length > 2) + goto dont_sort; + + if (inner->elements[0].negative) + goto dont_sort; + + if (dns_aclelement_match(clientaddr, NULL, + &inner->elements[0], + &ns_g_server->aclenv, + &matchelt)) { + if (inner->length == 2) { + dns_aclelement_t *elt1 = &inner->elements[1]; + if (elt1->type == dns_aclelementtype_nestedacl) + *argp = elt1->u.nestedacl; + else if (elt1->type == dns_aclelementtype_localhost && + ns_g_server->aclenv.localhost != NULL) + *argp = ns_g_server->aclenv.localhost; + else if (elt1->type == dns_aclelementtype_localnets && + ns_g_server->aclenv.localnets != NULL) + *argp = ns_g_server->aclenv.localnets; + else + goto dont_sort; + return (NS_SORTLISTTYPE_2ELEMENT); + } else { + INSIST(matchelt != NULL); + *argp = matchelt; + return (NS_SORTLISTTYPE_1ELEMENT); + } + } + } + + /* No match; don't sort. */ + dont_sort: + *argp = NULL; + return (NS_SORTLISTTYPE_NONE); +} + +int +ns_sortlist_addrorder2(isc_netaddr_t *addr, void *arg) { + dns_acl_t *sortacl = (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(isc_netaddr_t *addr, void *arg) { + dns_aclelement_t *matchelt = (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, + 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.2.4rc7/bin/named/tkeyconf.c b/contrib/bind-9.2.4rc7/bin/named/tkeyconf.c new file mode 100644 index 0000000000..0f7dad6d38 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/tkeyconf.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 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: tkeyconf.c,v 1.19.2.1 2004/03/09 06:09:20 marka Exp $ */ + +#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) + + +isc_result_t +ns_tkeyctx_fromconfig(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; + char *s; + isc_uint32_t n; + dns_fixedname_t fname; + dns_name_t *name; + isc_buffer_t b; + cfg_obj_t *obj; + + 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)); + RETERR(dst_key_fromfile(name, (dns_keytag_t) n, DNS_KEYALG_DH, + DST_TYPE_PUBLIC|DST_TYPE_PRIVATE, + 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.2.4rc7/bin/named/tsigconf.c b/contrib/bind-9.2.4rc7/bin/named/tsigconf.c new file mode 100644 index 0000000000..03f887abed --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/tsigconf.c @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 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: tsigconf.c,v 1.21.2.1 2004/03/09 06:09:20 marka Exp $ */ + +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include +#include + +static isc_result_t +add_initial_keys(cfg_obj_t *list, dns_tsig_keyring_t *ring, isc_mem_t *mctx) { + cfg_listelt_t *element; + cfg_obj_t *key = NULL; + char *keyid = NULL; + unsigned char *secret = NULL; + int secretalloc = 0; + int secretlen = 0; + isc_result_t ret; + isc_stdtime_t now; + + for (element = cfg_list_first(list); + element != NULL; + element = cfg_list_next(element)) + { + cfg_obj_t *algobj = NULL; + cfg_obj_t *secretobj = NULL; + dns_name_t keyname; + dns_name_t *alg; + char *algstr; + char keynamedata[1024]; + isc_buffer_t keynamesrc, keynamebuf; + 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) != ISC_R_SUCCESS) { + cfg_obj_log(algobj, ns_g_lctx, ISC_LOG_ERROR, + "key '%s': the only supported algorithm " + "is hmac-md5", keyid); + 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, NULL); + isc_mem_put(mctx, secret, secretalloc); + secret = NULL; + if (ret != ISC_R_SUCCESS) + goto failure; + } + + 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(cfg_obj_t *config, cfg_obj_t *vconfig, + isc_mem_t *mctx, dns_tsig_keyring_t **ringp) +{ + cfg_obj_t *maps[3]; + 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.2.4rc7/bin/named/unix/include/named/os.h b/contrib/bind-9.2.4rc7/bin/named/unix/include/named/os.h new file mode 100644 index 0000000000..ae28281561 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/unix/include/named/os.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2002 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: os.h,v 1.14.2.5 2004/03/09 06:09:24 marka Exp $ */ + +#ifndef NS_OS_H +#define NS_OS_H 1 + +#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_minprivs(void); + +void +ns_os_writepidfile(const char *filename, isc_boolean_t first_time); + +void +ns_os_shutdown(void); + +void +ns_os_tzset(void); + +#endif /* NS_OS_H */ diff --git a/contrib/bind-9.2.4rc7/bin/named/unix/os.c b/contrib/bind-9.2.4rc7/bin/named/unix/os.c new file mode 100644 index 0000000000..08cdcf349c --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/unix/os.c @@ -0,0 +1,569 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2002 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: os.c,v 1.46.2.9 2004/04/15 05:36:13 marka Exp $ */ + +#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 + +static char *pidfile = NULL; +static int devnullfd = -1; + +/* + * 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_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; + +#ifdef HAVE_LINUX_CAPABILITY_H + +static isc_boolean_t non_root = ISC_FALSE; +static isc_boolean_t non_root_caps = ISC_FALSE; + +/* + * 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 /* Required for syscall(). */ +#include /* Required for _LINUX_CAPABILITY_VERSION. */ + +#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 */ + +#ifndef SYS_capset +#ifndef __NR_capset +#include /* Slackware 4.0 needs this. */ +#endif +#define SYS_capset __NR_capset +#endif + +static void +linux_setcaps(unsigned int caps) { + struct __user_cap_header_struct caphead; + struct __user_cap_data_struct cap; + char strbuf[ISC_STRERRORSIZE]; + + if ((getuid() != 0 && !non_root_caps) || non_root) + return; + + 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 = caps; + if (syscall(SYS_capset, &caphead, &cap) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlyfatal("capset failed: %s", strbuf); + } +} + +static void +linux_initialprivs(void) { + unsigned int caps; + + /* + * 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. + */ + + caps = 0; + + /* + * We need to be able to bind() to privileged ports, notably port 53! + */ + caps |= (1 << CAP_NET_BIND_SERVICE); + + /* + * We need chroot() initially too. + */ + caps |= (1 << 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. + */ + caps |= (1 << CAP_SETUID); +#endif + + /* + * Since we call initgroups, we need this. + */ + caps |= (1 << CAP_SETGID); + + /* + * Without this, we run into problems reading a configuration file + * owned by a non-root user and non-world-readable on startup. + */ + caps |= (1 << 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. + */ + caps |= (1 << CAP_SYS_RESOURCE); + + linux_setcaps(caps); +} + +static void +linux_minprivs(void) { + unsigned int caps; + + /* + * 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. + */ + + caps = 0; + caps |= (1 << 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. + */ + caps |= (1 << CAP_SYS_RESOURCE); + + linux_setcaps(caps); +} + +#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, LOG_DAEMON); +} + +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]; + + pid = fork(); + if (pid == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlyfatal("fork(): %s", strbuf); + } + if (pid != 0) + _exit(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_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]; + if (root != NULL) { + if (chroot(root) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlyfatal("chroot(): %s", strbuf); + } + if (chdir("/") < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlyfatal("chdir(/): %s", strbuf); + } + } +} + +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) +#endif + ns_main_earlyfatal( + "-u not supported on Linux kernels older than " + "2.3.99-pre3 or 2.2.18 when using threads"); +#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_LINUX_CAPABILITY_H) && !defined(HAVE_LINUXTHREADS) + linux_minprivs(); +#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 { + (void)unlink(filename); + fd = open(filename, O_WRONLY|O_CREAT|O_EXCL, + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + } + return (fd); +} + +static void +cleanup_pidfile(void) { + if (pidfile != NULL) { + (void)unlink(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(); + + 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(); +} + +void +ns_os_tzset(void) { +#ifdef HAVE_TZSET + tzset(); +#endif +} diff --git a/contrib/bind-9.2.4rc7/bin/named/update.c b/contrib/bind-9.2.4rc7/bin/named/update.c new file mode 100644 index 0000000000..439e52f926 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/update.c @@ -0,0 +1,2634 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2003 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: update.c,v 1.88.2.13 2004/07/23 02:57:00 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 + +/* + * 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 { \ + result = (code); \ + update_log(client, zone, LOGLEVEL_PROTOCOL, \ + "update failed: %s (%s)", \ + msg, isc_result_totext(result)); \ + if (result != ISC_R_SUCCESS) goto failure; \ + } 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); +} + +/* + * Update a single RR in version 'ver' of 'db' and log the + * update in 'diff'. + * + * Ensures: + * '*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: + * '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; +} + +/* + * 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, *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 SIG and NXT even + * if we're normally not allowed to. + */ + if (rrset->type == dns_rdatatype_sig || + rrset->type == dns_rdatatype_nxt) + return (ISC_TRUE); + 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-minimial) "dns_diff_t" + * where each typle 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. + */ + +static isc_result_t +temp_check(isc_mem_t *mctx, dns_diff_t *temp, dns_db_t *db, + dns_dbversion_t *ver) +{ + isc_result_t result; + dns_name_t *name; + dns_dbnode_t *node; + dns_difftuple_t *t; + dns_diff_t trash; + + /* Exit early if the list is empty (for efficiency only). */ + if (ISC_LIST_HEAD(temp->tuples) == NULL) + return (ISC_R_SUCCESS); + + /* + * Sort the prerequisite records by owner name, + * type, and rdata. + */ + result = dns_diff_sort(temp, temp_order); + if (result != ISC_R_SUCCESS) + return (result); + + 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; + + /* A new unique name begins here. */ + node = NULL; + result = dns_db_findnode(db, name, ISC_FALSE, &node); + if (result == ISC_R_NOTFOUND) + return (DNS_R_NXRRSET); + if (result != ISC_R_SUCCESS) + 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 */ + + type = t->rdata.type; + if (type == dns_rdatatype_sig) + covers = dns_rdata_covers(&t->rdata); + 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); + 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 'update_rr' is neither a SOA nor an NS RR. + */ +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) ? + 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 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 NXT or DNAME, but multiple NXTs 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_nxt) + 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 NXTs and SIGs. + */ + +#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 = { NULL, 0, 0, 0, 0, + { (void*)(-1), (void*)(-1) } }; + 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; + result = dns_dbiterator_current(dbit, &node, child); + dns_db_detachnode(db, &node); + CHECK(result); + 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_nxt_rrset_exists(). + */ +static isc_result_t +is_non_nxt_action(void *data, dns_rdataset_t *rrset) { + UNUSED(data); + if (!(rrset->type == dns_rdatatype_nxt || + (rrset->type == dns_rdatatype_sig && + rrset->covers == dns_rdatatype_nxt))) + return (ISC_R_EXISTS); + return (ISC_R_SUCCESS); +} + +/* + * Check whether there is an rrset other than a NXT or SIG NXT, + * 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_nxt_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_nxt_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_glue(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, + isc_boolean_t *flag) +{ + 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) { + *flag = ISC_FALSE; + return (ISC_R_SUCCESS); + } else if (result == DNS_R_ZONECUT) { + /* + * We are at the zonecut. The name will have an NXT, but + * non-delegation will be omitted from the type bit map. + */ + *flag = ISC_FALSE; + return (ISC_R_SUCCESS); + } else if (result == DNS_R_GLUE || result == DNS_R_DNAME) { + *flag = ISC_TRUE; + return (ISC_R_SUCCESS); + } else { + return (result); + } +} + +/* + * Find the next/previous name that has a NXT record. + * In other words, skip empty database nodes and names that + * have had their NXTs removed because they are obscured by + * a zone cut. + */ +static isc_result_t +next_active(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_nxt; + 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) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_UPDATE, + NS_LOGMODULE_UPDATE, + ISC_LOG_ERROR, + "secure zone with no NXTs"); + result = DNS_R_BADZONE; + goto failure; + } + } + 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_nxt, 0, &has_nxt)); + + } while (! has_nxt); + failure: + if (dbit != NULL) + dns_dbiterator_destroy(&dbit); + + return (result); +} + +/* + * Add a NXT record for "name", recording the change in "diff". + * The existing NXT is removed. + */ +static isc_result_t +add_nxt(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_diff_t *diff) +{ + isc_result_t result; + dns_dbnode_t *node = NULL; + unsigned char buffer[DNS_NXT_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 NXT target. + */ + CHECK(next_active(db, ver, name, target, ISC_TRUE)); + + /* + * Create the NXT RDATA. + */ + CHECK(dns_db_findnode(db, name, ISC_FALSE, &node)); + dns_rdata_init(&rdata); + CHECK(dns_nxt_buildrdata(db, ver, node, target, buffer, &rdata)); + dns_db_detachnode(db, &node); + + /* + * Delete the old NXT and record the change. + */ + CHECK(delete_if(true_p, db, ver, name, dns_rdatatype_nxt, 0, + NULL, diff)); + /* + * Add the new NXT and record the change. + */ + CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, + 3600, /* XXXRTH */ + &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 NXT record for "name", recording the change in "diff". + */ +static isc_result_t +add_placeholder_nxt(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_nxt, &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_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; + CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node)); + CHECK(dns_dnssec_findzonekeys(db, ver, node, dns_db_origin(db), + mctx, maxkeys, keys, nkeys)); + failure: + if (node != NULL) + dns_db_detachnode(db, &node); + return (result); +} + +/* + * Add SIG records for an RRset, recording the change in "diff". + */ +static isc_result_t +add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, + dns_rdatatype_t type, dns_diff_t *diff, dst_key_t **keys, + unsigned int nkeys, isc_mem_t *mctx, isc_stdtime_t inception, + isc_stdtime_t expire) +{ + isc_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; + + 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++) { + /* Calculate the signature, creating a SIG RDATA. */ + CHECK(dns_dnssec_sign(name, &rdataset, keys[i], + &inception, &expire, + mctx, &buffer, &sig_rdata)); + + /* Update the database and journal with the SIG. */ + /* 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); + } + + failure: + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + if (node != NULL) + dns_db_detachnode(db, &node); + return (result); +} + +/* + * Update SIG and NXT records affected by an update. The original + * update, including the SOA serial update but exluding the SIG & NXT + * changes, is in "diff" and has already been applied to "newver" of "db". + * The database version prior to the update is "oldver". + * + * The necessary SIG and NXT changes will be applied to "newver" + * and added (as a minimal diff) to "diff". + * + * The SIGs generated will be valid for 'sigvalidityinterval' seconds. + */ +static isc_result_t +update_signatures(isc_mem_t *mctx, 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 nxt_diff; + dns_diff_t nxt_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_diff_init(mctx, &diffnames); + dns_diff_init(mctx, &affected); + + dns_diff_init(mctx, &sig_diff); + dns_diff_init(mctx, &nxt_diff); + dns_diff_init(mctx, &nxt_mindiff); + + result = find_zone_keys(db, newver, mctx, + MAXZONEKEYS, zone_keys, &nkeys); + if (result != ISC_R_SUCCESS) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_UPDATE, + NS_LOGMODULE_UPDATE, 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; + + /* + * Find all RRsets directly affected by the update, and + * update their SIGs. 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 SIGs. */ + if (type == dns_rdatatype_sig) + goto skip; + + /* + * Delete all old SIGs 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_sig, type, + NULL, &sig_diff)); + + /* + * If this RRset still exists after the update, + * add a new signature for it. + */ + CHECK(rrset_exists(db, newver, name, type, 0, &flag)); + if (flag) { + CHECK(add_sigs(db, newver, name, type, + &sig_diff, zone_keys, nkeys, + mctx, inception, expire)); + } + 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 NXTs and SIG NXTs. */ + for (t = ISC_LIST_HEAD(diffnames.tuples); + t != NULL; + t = ISC_LIST_NEXT(t, link)) + { + CHECK(non_nxt_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 NXT 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 NXTs 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(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 NXT 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 NXTs, and delete/create + * NXTs to make it so. We don't know the final NXT targets yet, + * so we just create placeholder NXTs with arbitrary contents + * to indicate that their respective owner names should be part of + * the NXT chain. + */ + for (t = ISC_LIST_HEAD(affected.tuples); + t != NULL; + t = ISC_LIST_NEXT(t, link)) + { + isc_boolean_t exists; + CHECK(name_exists(db, newver, &t->name, &exists)); + if (! exists) + continue; + CHECK(is_glue(db, newver, &t->name, &flag)); + if (flag) { + /* + * This name is obscured. Delete any + * existing NXT record. + */ + CHECK(delete_if(true_p, db, newver, &t->name, + dns_rdatatype_nxt, 0, + NULL, &nxt_diff)); + } else { + /* + * This name is not obscured. It should have a NXT. + */ + CHECK(rrset_exists(db, newver, &t->name, + dns_rdatatype_nxt, 0, &flag)); + if (! flag) { + add_placeholder_nxt(db, newver, &t->name, + diff); + } + } + } + + /* + * Now we know which names are part of the NXT 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_nxt, 0, &flag)); + if (flag) { + /* + * There is a NXT, 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 SIG bit should always be set in the NXTs + * we generate, because they will all get SIG NXTs. + * (XXX what if the zone keys are missing?). + * Because the SIG NXTs have not necessarily been + * created yet, the correctness of the bit mask relies + * on the assumption that NXTs are only created if + * there is other data, and if there is other data, + * there are other SIGs. + */ + CHECK(add_nxt(db, newver, &t->name, &nxt_diff)); + } + } + + /* + * Minimize the set of NXT updates so that we don't + * have to regenerate the SIG NXTs for NXTs that were + * replaced with identical ones. + */ + while ((t = ISC_LIST_HEAD(nxt_diff.tuples)) != NULL) { + ISC_LIST_UNLINK(nxt_diff.tuples, t, link); + dns_diff_appendminimal(&nxt_mindiff, &t); + } + + /* Update SIG NXTs. */ + for (t = ISC_LIST_HEAD(nxt_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_sig, dns_rdatatype_nxt, + NULL, &sig_diff)); + } else if (t->op == DNS_DIFFOP_ADD) { + CHECK(add_sigs(db, newver, &t->name, dns_rdatatype_nxt, + &sig_diff, zone_keys, nkeys, mctx, + inception, expire)); + } 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(nxt_mindiff.tuples)) != NULL) { + ISC_LIST_UNLINK(nxt_mindiff.tuples, t, link); + dns_diff_appendminimal(diff, &t); + } + + INSIST(ISC_LIST_EMPTY(sig_diff.tuples)); + INSIST(ISC_LIST_EMPTY(nxt_diff.tuples)); + INSIST(ISC_LIST_EMPTY(nxt_mindiff.tuples)); + + failure: + dns_diff_clear(&sig_diff); + dns_diff_clear(&nxt_diff); + dns_diff_clear(&nxt_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: + if (dns_zone_getforwardacl(zone) == NULL) { + result = DNS_R_NOTIMP; + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, ISC_LOG_ERROR, + "update forwarding denied"); + goto failure; + } + CHECK(ns_client_checkacl(client, "update forwarding", + dns_zone_getforwardacl(zone), + ISC_FALSE, ISC_LOG_ERROR)); + CHECK(send_forward_event(client, zone)); + break; + default: + FAILC(DNS_R_NOTAUTH, + "not authoritative for update zone"); + } + return; + + failure: + /* + * 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); +} + +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; + + 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) + FAILC(DNS_R_FORMERR, "prerequisite TTL is not zero"); + + if (! dns_name_issubdomain(name, zonename)) + FAILC(DNS_R_NOTZONE, + "prerequisite name is out of zone"); + + if (update_class == dns_rdataclass_any) { + if (rdata.length != 0) + FAILC(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) { + FAILC(DNS_R_NXDOMAIN, + "'name in use' prerequisite " + "not satisfied"); + } + } else { + CHECK(rrset_exists(db, ver, name, + rdata.type, covers, &flag)); + if (! flag) { + /* RRset does not exist. */ + FAILC(DNS_R_NXRRSET, + "'rrset exists (value independent)' " + "prerequisite not satisfied"); + } + } + } else if (update_class == dns_rdataclass_none) { + if (rdata.length != 0) + FAILC(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) { + FAILC(DNS_R_YXDOMAIN, + "'name not in use' prerequisite " + "not satisfied"); + } + } else { + CHECK(rrset_exists(db, ver, name, + rdata.type, covers, &flag)); + if (flag) { + /* RRset exists. */ + FAILC(DNS_R_YXRRSET, + "'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 { + FAILC(DNS_R_FORMERR, "malformed prerequisite"); + } + } + if (result != ISC_R_NOMORE) + FAIL(result); + + /* + * Perform the final check of the "rrset exists (value dependent)" + * prerequisites. + */ + result = temp_check(mctx, &temp, db, ver); + if (result != ISC_R_SUCCESS) + FAILC(result, "'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. + */ + if (ssutable == NULL) { + char msg[DNS_RDATACLASS_FORMATSIZE + DNS_NAME_FORMATSIZE + + sizeof("update '/'")]; + ns_client_aclmsg("update", zonename, client->view->rdclass, + msg, sizeof(msg)); + CHECK(ns_client_checkacl(client, msg, + dns_zone_getupdateacl(zone), + ISC_FALSE, ISC_LOG_ERROR)); + } else if (client->signer == NULL) { + /* This gets us a free log message. */ + char msg[DNS_RDATACLASS_FORMATSIZE + DNS_NAME_FORMATSIZE + + sizeof("update '/'")]; + ns_client_aclmsg("update", zonename, client->view->rdclass, + msg, sizeof(msg)); + CHECK(ns_client_checkacl(client, msg, NULL, ISC_FALSE, + ISC_LOG_ERROR)); + } + + /* + * 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"); + } + } 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 NXT records." + */ + if (dns_db_issecure(db)) { + if (rdata.type == dns_rdatatype_nxt) { + FAILC(DNS_R_REFUSED, + "explicit NXT updates are not allowed " + "in secure zones"); + } + else if (rdata.type == dns_rdatatype_sig) { + FAILC(DNS_R_REFUSED, + "explicit SIG 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. + */ + + 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) { + 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; + } + + update_log(client, zone, + LOGLEVEL_PROTOCOL, "adding an RR"); + + /* 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) { + update_log(client, zone, + LOGLEVEL_PROTOCOL, + "delete all rrsets from a name"); + 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(true_p, 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 { + update_log(client, zone, + LOGLEVEL_PROTOCOL, + "deleting an rrset"); + 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 SIGs and NXTs (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)); + } + + if (dns_db_issecure(db)) { + result = update_signatures(mctx, db, oldver, ver, + &diff, dns_zone_getsigvalidityinterval(zone)); + if (result != ISC_R_SUCCESS) { + update_log(client, zone, + ISC_LOG_ERROR, + "SIG/NXT 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); + + if (zone != NULL) + dns_zone_detach(&zone); + + isc_task_detach(&task); + uev->result = result; + 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); + client->nupdates--; + respond(client, uev->result); + ns_client_detach(&client); + isc_event_free(&event); +} + +/* + * 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); + ns_client_detach(&client); + isc_event_free(&event); +} + + +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; + + if (result != ISC_R_SUCCESS) { + INSIST(answer == NULL); + uev->ev_type = DNS_EVENT_UPDATEDONE; + uev->ev_action = forward_fail; + } else { + uev->ev_type = DNS_EVENT_UPDATEDONE; + uev->ev_action = forward_done; + uev->answer = answer; + } + isc_task_send(client->task, ISC_EVENT_PTR(&uev)); +} + +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); + } + dns_zone_detach(&zone); + 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.2.4rc7/bin/named/xfrout.c b/contrib/bind-9.2.4rc7/bin/named/xfrout.c new file mode 100644 index 0000000000..8823a7a01e --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/xfrout.c @@ -0,0 +1,1709 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001, 2003 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: xfrout.c,v 1.101.2.8 2004/04/15 01:38:05 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 + +/* + * 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; + +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 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->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->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) { + dns_dbiterator_pause(it->dbit); +} + +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; + 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_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; +} 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_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, unsigned 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[DNS_RDATACLASS_FORMATSIZE + DNS_NAME_FORMATSIZE + + sizeof("zone transfer '/'")]; + isc_boolean_t is_poll = ISC_FALSE; + + 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) + FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", + question_name, question_class); + 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); + + 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. + */ + ns_client_aclmsg("zone transfer", question_name, + client->view->rdclass, msg, sizeof(msg)); + CHECK(ns_client_checkacl(client, msg, + dns_zone_getxfracl(zone), ISC_TRUE, + ISC_LOG_ERROR)); + + /* + * 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. + */ + 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 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. + */ + CHECK(xfrout_ctx_create(mctx, client, request->id, question_name, + reqtype, question_class, 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)); + stream = NULL; + quota = NULL; + + CHECK(xfr->stream->methods->first(xfr->stream)); + + if (is_poll) + xfrout_log1(client, question_name, question_class, + ISC_LOG_DEBUG(1), "IXFR poll up to date"); + else + xfrout_log1(client, question_name, question_class, + ISC_LOG_INFO, "%s started", mnemonic); + + /* + * 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 (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_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->db = NULL; + xfr->ver = NULL; + 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->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 possiby 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; + 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; + 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)); + 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->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. */ + xfrout_log(xfr, ISC_LOG_DEBUG(6), + "end of transfer"); + 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, unsigned 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.2.4rc7/bin/named/zoneconf.c b/contrib/bind-9.2.4rc7/bin/named/zoneconf.c new file mode 100644 index 0000000000..3f20d7786b --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/named/zoneconf.c @@ -0,0 +1,613 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 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: zoneconf.c,v 1.87.2.6 2004/03/09 06:09:20 marka Exp $ */ + +#include + +#include +#include +#include /* Required for HP/UX (and others?) */ +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * 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(cfg_obj_t *zconfig, cfg_obj_t *vconfig, cfg_obj_t *config, + const char *aclname, ns_aclconfctx_t *actx, + dns_zone_t *zone, + void (*setzacl)(dns_zone_t *, dns_acl_t *), + void (*clearzacl)(dns_zone_t *)) +{ + isc_result_t result; + cfg_obj_t *maps[4]; + cfg_obj_t *aclobj = NULL; + int i = 0; + dns_acl_t *dacl = NULL; + + if (zconfig != NULL) + maps[i++] = cfg_tuple_get(zconfig, "options"); + if (vconfig != NULL) + maps[i++] = cfg_tuple_get(vconfig, "options"); + if (config != NULL) { + cfg_obj_t *options = NULL; + (void)cfg_map_get(config, "options", &options); + if (options != NULL) + maps[i++] = options; + } + maps[i] = NULL; + + result = ns_config_get(maps, aclname, &aclobj); + if (aclobj == NULL) { + (*clearzacl)(zone); + return (ISC_R_SUCCESS); + } + + result = ns_acl_fromconfig(aclobj, config, actx, + dns_zone_getmctx(zone), &dacl); + if (result != ISC_R_SUCCESS) + return (result); + (*setzacl)(zone, dacl); + dns_acl_detach(&dacl); + return (ISC_R_SUCCESS); +} + +/* + * Parse the zone update-policy statement. + */ +static isc_result_t +configure_zone_ssutable(cfg_obj_t *zconfig, dns_zone_t *zone) { + cfg_obj_t *updatepolicy = NULL; + 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) + 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)) + { + cfg_obj_t *stmt = cfg_listelt_value(element); + cfg_obj_t *mode = cfg_tuple_get(stmt, "mode"); + cfg_obj_t *identity = cfg_tuple_get(stmt, "identity"); + cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype"); + cfg_obj_t *dname = cfg_tuple_get(stmt, "name"); + cfg_obj_t *typelist = cfg_tuple_get(stmt, "types"); + 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 + 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)) + { + cfg_obj_t *typeobj; + isc_textregion_t r; + + INSIST(i < n); + + typeobj = cfg_listelt_value(element2); + str = cfg_obj_asstring(typeobj); + r.base = str; + 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(cfg_obj_t *map) { + 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)); +} + +isc_result_t +ns_zone_configure(cfg_obj_t *config, cfg_obj_t *vconfig, cfg_obj_t *zconfig, + ns_aclconfctx_t *ac, dns_zone_t *zone) +{ + isc_result_t result; + char *zname; + dns_rdataclass_t zclass; + dns_rdataclass_t vclass; + cfg_obj_t *maps[5]; + cfg_obj_t *zoptions = NULL; + cfg_obj_t *options = NULL; + 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; + + 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 = cfg_obj_asstring(obj); + else + cpval = default_dbtype; + RETERR(strtoargv(mctx, cpval, &dbargc, &dbargv)); + /* + * 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. + */ + RETERR(dns_zone_setdbtype(zone, dbargc, (const char * const *)dbargv)); + isc_mem_put(mctx, dbargv, dbargc * sizeof(*dbargv)); + + obj = NULL; + result = cfg_map_get(zoptions, "file", &obj); + if (result == ISC_R_SUCCESS) + filename = cfg_obj_asstring(obj); + RETERR(dns_zone_setfile(zone, filename)); + + 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 { + 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); + dns_zone_setstatistics(zone, cfg_obj_asboolean(obj)); + + /* + * 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 { + char *notifystr = cfg_obj_asstring(obj); + if (strcasecmp(notifystr, "explicit") == 0) + notifytype = dns_notifytype_explicit; + 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); + 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); + dns_zone_setnotifysrc6(zone, cfg_obj_assockaddr(obj)); + ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); + + 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); + } + + /* + * 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); + } 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: + 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); + + 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); + 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); + dns_zone_setxfrsource6(zone, cfg_obj_assockaddr(obj)); + ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); + + break; + + default: + break; + } + + return (ISC_R_SUCCESS); +} + +isc_boolean_t +ns_zone_reusable(dns_zone_t *zone, cfg_obj_t *zconfig) { + cfg_obj_t *zoptions = NULL; + 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.2.4rc7/bin/nsupdate/nsupdate.8 b/contrib/bind-9.2.4rc7/bin/nsupdate/nsupdate.8 new file mode 100644 index 0000000000..3697e83584 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/nsupdate/nsupdate.8 @@ -0,0 +1,347 @@ +.\" Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2000, 2001, 2003 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: nsupdate.8,v 1.24.2.4 2004/03/15 04:44:41 marka Exp $ +.\" +.TH "NSUPDATE" "8" "Jun 30, 2000" "BIND9" "" +.SH NAME +nsupdate \- Dynamic DNS update utility +.SH SYNOPSIS +.sp +\fBnsupdate\fR [ \fB-d\fR ] [ \fB [ -y \fIkeyname:secret\fB ] [ -k \fIkeyfile\fB ] \fR ] [ \fB-v\fR ] [ \fBfilename\fR ] +.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. +The signatures rely 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. +\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. +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 +\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 +By default +\fBnsupdate\fR +uses UDP to send update requests to the name server. +The +\fB-v\fR +option makes +\fBnsupdate\fR +use a TCP connection. +This may be preferable when a batch of update requests is made. +.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: +.TP +\fBserver servername [ port ]\fR +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. +.TP +\fBlocal address [ port ]\fR +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. +.TP +\fBzone zonename\fR +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. +.TP +\fBclass classname\fR +Specify the default class. +If no \fIclass\fR is specified the default class is +\fIIN\fR. +.TP +\fBkey name secret\fR +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. +.TP +\fBprereq nxdomain domain-name\fR +Requires that no resource record of any type exists with name +\fIdomain-name\fR. +.TP +\fBprereq yxdomain domain-name\fR +Requires that +\fIdomain-name\fR +exists (has as at least one resource record, of any type). +.TP +\fBprereq nxrrset domain-name [ class ] type\fR +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. +.TP +\fBprereq yxrrset domain-name [ class ] type\fR +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. +.TP +\fBprereq yxrrset domain-name [ class ] type data\fI...\fB\fR +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. +.TP +\fBupdate delete domain-name [ ttl ] [ class ] [ type [ data\fI...\fB ] ]\fR +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. +.TP +\fBupdate add domain-name ttl [ class ] type data\fI...\fB\fR +Adds a new resource record with the specified +\fIttl\fR, +\fIclass\fR +and +\fIdata\fR. +.TP +\fBshow\fR +Displays the current message, containing all of the prerequisites and +updates specified since the last send. +.TP +\fBsend\fR +Sends the current message. This is equivalent to entering a blank line. +.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 +.nf +# nsupdate +> update delete oldhost.example.com A +> update add newhost.example.com 86400 A 172.16.1.1 +> send +.sp +.fi +.PP +Any A records for +\fBoldhost.example.com\fR +are deleted. +and an A record for +\fBnewhost.example.com\fR +it IP address 172.16.1.1 is added. +The newly-added record has a 1 day TTL (86400 seconds) +.sp +.nf +# nsupdate +> prereq nxdomain nickname.example.com +> update add nickname.example.com 86400 CNAME somehost.example.com +> send +.sp +.fi +.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 +SIG, KEY and NXT records.) +.SH "FILES" +.TP +\fB/etc/resolv.conf\fR +used to identify default name server +.TP +\fBK{name}.+157.+{random}.key\fR +base-64 encoding of HMAC-MD5 key created by +\fBdnssec-keygen\fR(8). +.TP +\fBK{name}.+157.+{random}.private\fR +base-64 encoding of HMAC-MD5 key created by +\fBdnssec-keygen\fR(8). +.SH "SEE ALSO" +.PP +\fBRFC2136\fR, +\fBRFC3007\fR, +\fBRFC2104\fR, +\fBRFC2845\fR, +\fBRFC1034\fR, +\fBRFC2535\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. diff --git a/contrib/bind-9.2.4rc7/bin/nsupdate/nsupdate.c b/contrib/bind-9.2.4rc7/bin/nsupdate/nsupdate.c new file mode 100644 index 0000000000..710418d0eb --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/nsupdate/nsupdate.c @@ -0,0 +1,1974 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2003 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: nsupdate.c,v 1.103.2.23 2004/05/12 04:46:17 marka Exp $ */ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#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 NAMEBUF 512 +#define WORDLEN 512 +#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_taskmgr_t *taskmgr = NULL; +static isc_task_t *global_task = NULL; +static isc_event_t *global_event = 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_tsigkey_t *key = NULL; +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 char *keystr = NULL, *keyfile = NULL; +static isc_entropy_t *entp = 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 dns_rdataclass_t defaultclass = dns_rdataclass_in; +static dns_rdataclass_t zoneclass = dns_rdataclass_none; + +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); + +#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 + +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 +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; +} + +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; + dns_fixedname_t fkeyname; + dns_name_t *keyname; + + dns_fixedname_init(&fkeyname); + keyname = dns_fixedname_name(&fkeyname); + + debug("Creating key..."); + + s = strchr(keystr, ':'); + if (s == NULL || s == keystr || *s == 0) + fatal("key option must specify keyname:secret"); + secretstr = s + 1; + + isc_buffer_init(&keynamesrc, keystr, s - keystr); + isc_buffer_add(&keynamesrc, s - keystr); + + 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, dns_tsig_hmacmd5_name, + secret, secretlen, ISC_TRUE, NULL, + 0, 0, mctx, NULL, &key); + if (result != ISC_R_SUCCESS) + fprintf(stderr, "could not create key from %s: %s\n", + keystr, dns_result_totext(result)); + failure: + if (secret != NULL) + isc_mem_free(mctx, secret); +} + +static void +setup_keyfile(void) { + dst_key_t *dstkey = NULL; + isc_result_t result; + + debug("Creating key..."); + + result = dst_key_fromnamedfile(keyfile, DST_TYPE_PRIVATE, mctx, + &dstkey); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not read key from %s: %s\n", + keyfile, isc_result_totext(result)); + return; + } + result = dns_tsigkey_createfromkey(dst_key_name(dstkey), + dns_tsig_hmacmd5_name, + dstkey, ISC_FALSE, NULL, + 0, 0, mctx, NULL, &key); + 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; + } +} + +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 (key != NULL) { + ddebug("Freeing key"); + dns_tsigkey_detach(&key); + } + + if (updatemsg != NULL) + dns_message_destroy(&updatemsg); + + if (is_dst_up) { + ddebug("Destroy DST lib"); + dst_lib_destroy(); + is_dst_up = ISC_FALSE; + } + + if (entp != NULL) { + ddebug("Detach from entropy"); + isc_entropy_detach(&entp); + } + + 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; + + 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_mem_create(0, 0, &mctx); + check_result(result, "isc_mem_create"); + + 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); + } + } + } + + result = isc_entropy_create(mctx, &entp); + check_result(result, "isc_entropy_create"); + + result = isc_hash_create(mctx, entp, DNS_NAME_MAXWIRE); + check_result(result, "isc_hash_create"); + isc_hash_init(); + + result = dns_dispatchmgr_create(mctx, entp, &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, entp, 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) { + struct in_addr in4; + struct in6_addr in6; +#ifdef USE_GETADDRINFO + struct addrinfo *res = NULL, hints; + int result; +#else + struct hostent *he; +#endif + + ddebug("get_address()"); + + /* + * Assume we have v4 if we don't have v6, since setup_libs + * fatal()'s out if we don't have either. + */ + if (have_ipv6 && inet_pton(AF_INET6, host, &in6) == 1) + isc_sockaddr_fromin6(sockaddr, &in6, port); + else if (inet_pton(AF_INET, host, &in4) == 1) + isc_sockaddr_fromin(sockaddr, &in4, port); + else { +#ifdef USE_GETADDRINFO + memset(&hints, 0, sizeof(hints)); + if (!have_ipv6) + hints.ai_family = PF_INET; + else if (!have_ipv4) + hints.ai_family = PF_INET6; + else { + hints.ai_family = PF_UNSPEC; +#ifdef AI_ADDRCONFIG + hints.ai_flags = AI_ADDRCONFIG; +#endif + } + debug ("before getaddrinfo()"); + isc_app_block(); +#ifdef AI_ADDRCONFIG + again: +#endif + result = getaddrinfo(host, NULL, &hints, &res); +#ifdef AI_ADDRCONFIG + if (result == EAI_BADFLAGS && + (hints.ai_flags & AI_ADDRCONFIG) != 0) { + hints.ai_flags &= ~AI_ADDRCONFIG; + goto again; + } +#endif + isc_app_unblock(); + if (result != 0) { + fatal("couldn't find server '%s': %s", + host, gai_strerror(result)); + } + memcpy(&sockaddr->type.sa,res->ai_addr, res->ai_addrlen); + sockaddr->length = res->ai_addrlen; + isc_sockaddr_setport(sockaddr, port); + freeaddrinfo(res); +#else + debug ("before gethostbyname()"); + isc_app_block(); + he = gethostbyname(host); + isc_app_unblock(); + if (he == NULL) + fatal("couldn't find server '%s' (h_errno=%d)", + host, h_errno); + INSIST(he->h_addrtype == AF_INET); + isc_sockaddr_fromin(sockaddr, + (struct in_addr *)(he->h_addr_list[0]), + port); +#endif + } +} + +static void +parse_args(int argc, char **argv) { + int ch; + isc_result_t result; + + debug("parse_args"); + while ((ch = isc_commandline_parse(argc, argv, "dDMy:vk:")) != -1) { + switch (ch) { + case 'd': + debugging = ISC_TRUE; + break; + case 'D': /* was -dd */ + debugging = ISC_TRUE; + ddebugging = ISC_TRUE; + break; + case 'M': /* was -dm */ + debugging = ISC_TRUE; + ddebugging = ISC_TRUE; + memdebugging = ISC_TRUE; + isc_mem_debugging = ISC_MEM_DEBUGTRACE | + ISC_MEM_DEBUGRECORD; + break; + case 'y': + keystr = isc_commandline_argument; + break; + case 'v': + usevc = ISC_TRUE; + break; + case 'k': + keyfile = isc_commandline_argument; + break; + default: + fprintf(stderr, "%s: invalid argument -%c\n", + argv[0], ch); + fprintf(stderr, "usage: nsupdate [-d] " + "[-y keyname:secret | -k keyfile] [-v] " + "[filename]\n"); + exit(1); + } + } + if (keyfile != NULL && keystr != NULL) { + fprintf(stderr, "%s: cannot specify both -k and -y\n", + argv[0]); + exit(1); + } + + 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, NAMEBUF); + 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, ISC_FALSE, 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; + + 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); + + 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 (key != NULL) + dns_tsigkey_detach(&key); + result = dns_tsigkey_create(keyname, dns_tsig_hmacmd5_name, + secret, secretlen, ISC_TRUE, NULL, 0, 0, + mctx, NULL, &key); + 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); + } + 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; + unsigned long 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; + char *endp; + 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; + } + } + ttl = strtoul(word, &endp, 10); + if (!isdigit((unsigned char)*word) || *endp != '\0') { + if (isdelete) { + ttl = 0; + goto parseclass; + } else { + fprintf(stderr, "ttl '%s' is not legal\n", word); + 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); + 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) { + 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); + if (rdata != NULL) + 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 +show_message(dns_message_t *msg) { + isc_result_t result; + isc_buffer_t *buf = NULL; + int bufsz; + + ddebug("show_message()"); + 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; + } + printf("Outgoing update query:\n%.*s", + (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, "> "); + 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(updatemsg); + return (STATUS_MORE); + } + if (strcasecmp(word, "key") == 0) + return (evaluate_key(cmdline)); + 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 (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_message_t *rcvmsg = NULL; + 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, &rcvmsg); + check_result(result, "dns_message_create"); + result = dns_request_getresponse(request, rcvmsg, + DNS_MESSAGEPARSE_PRESERVEORDER); + switch (result) { + case ISC_R_SUCCESS: + break; + case DNS_R_CLOCKSKEW: + case DNS_R_EXPECTEDTSIG: + case DNS_R_TSIGERRORSET: + case DNS_R_TSIGVERIFYFAILURE: + case DNS_R_UNEXPECTEDTSIG: + fprintf(stderr, "; TSIG error with server: %s\n", + isc_result_totext(result)); + seenerror = ISC_TRUE; + break; + default: + check_result(result, "dns_request_getresponse"); + } + + if (rcvmsg->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(rcvmsg->rcode, &b); + check_result(result, "dns_rcode_totext"); + rds = dns_message_gettsig(rcvmsg, NULL); + if (rds != NULL) + check_tsig_error(rds, &b); + fprintf(stderr, "update failed: %.*s\n", + (int)isc_buffer_usedlength(&b), buf); + } + } + if (debugging) { + isc_buffer_t *buf = NULL; + int bufsz; + + 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(rcvmsg, style, 0, buf); + bufsz *= 2; + } while (result == ISC_R_NOSPACE); + check_result(result, "dns_message_totext"); + fprintf(stderr, "\nReply from update query:\n%.*s\n", + (int)isc_buffer_usedlength(buf), + (char*)isc_buffer_base(buf)); + isc_buffer_free(&buf); + } + dns_message_destroy(&rcvmsg); + done: + dns_request_destroy(&request); + 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; + dns_name_t *name = NULL; + dns_rdataset_t *rdataset = NULL; + unsigned int options = 0; + + ddebug("send_update()"); + + 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); + + if (usevc) + options |= DNS_REQUESTOPT_TCP; + result = dns_request_createvia(requestmgr, updatemsg, srcaddr, + master, options, key, + FIND_TIMEOUT, global_task, + update_completed, NULL, &request); + check_result(result, "dns_request_createvia"); + 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; + isc_sockaddr_t *serveraddr, tempaddr; + dns_name_t *zonename; + nsu_requestinfo_t *reqinfo; + dns_message_t *soaquery = NULL; + isc_sockaddr_t *addr; + isc_boolean_t seencname = ISC_FALSE; + + 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); + 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)); + + 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_createvia(requestmgr, soaquery, + localaddr, addr, 0, NULL, + FIND_TIMEOUT, 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) { + isc_buffer_t *buf = NULL; + int bufsz; + bufsz = INITTEXT; + do { + if (buf != NULL) + isc_buffer_free(&buf); + if (bufsz > MAXTEXT) { + fprintf(stderr, "could not allocate enough " + "space for debugging message\n"); + exit(1); + } + result = isc_buffer_allocate(mctx, &buf, bufsz); + check_result(result, "isc_buffer_allocate"); + result = dns_message_totext(rcvmsg, style, 0, buf); + } while (result == ISC_R_NOSPACE); + check_result(result, "dns_message_totext"); + fprintf(stderr, "Reply from SOA query:\n%.*s\n", + (int)isc_buffer_usedlength(buf), + (char*)isc_buffer_base(buf)); + isc_buffer_free(&buf); + } + + if (rcvmsg->rcode != dns_rcode_noerror && + rcvmsg->rcode != dns_rcode_nxdomain) + fatal("response to SOA query was unsuccessful"); + + lookforsoa: + if (pass == 0) + section = DNS_SECTION_ANSWER; + else if (pass == 1) + section = DNS_SECTION_AUTHORITY; + else + fatal("response to SOA query didn't contain an SOA"); + + + 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) { + dns_name_t tname; + unsigned int nlabels; + + 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); + if (userserver != NULL) + sendrequest(localaddr, userserver, soaquery, &request); + else + sendrequest(localaddr, &servers[ns_inuse], soaquery, + &request); + goto out; + } + + 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; + } + + send_update(zonename, serveraddr, localaddr); + + dns_message_destroy(&soaquery); + dns_request_destroy(&request); + + out: + setzoneclass(dns_rdataclass_none); + dns_rdata_freestruct(&soa); + dns_message_destroy(&rcvmsg); + ddebug("Out of recvsoa"); +} + +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_createvia(requestmgr, msg, srcaddr, destaddr, 0, + (userserver != NULL) ? key : NULL, + FIND_TIMEOUT, global_task, + recvsoa, reqinfo, request); + check_result(result, "dns_request_createvia"); + requests++; +} + +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()"); + + 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) { + done_update(); + return; + } + + if (userzone != NULL && userserver != NULL) { + 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"); + + 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); + + 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()"); + + 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 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(); + + parse_args(argc, argv); + + 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.2.4rc7/bin/nsupdate/nsupdate.html b/contrib/bind-9.2.4rc7/bin/nsupdate/nsupdate.html new file mode 100644 index 0000000000..9fd1afcbdb --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/nsupdate/nsupdate.html @@ -0,0 +1,984 @@ + + + + +nsupdate

nsupdate

Name

nsupdate -- Dynamic DNS update utility

Synopsis

nsupdate [-d] [-y keyname:secret | -k keyfile] [-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. +The signatures rely 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. +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. +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 +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.

By default +nsupdate +uses UDP to send update requests to the name server. +The +-v +option makes +nsupdate +use a TCP connection. +This may be preferable when a batch of update requests is made.

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.

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 +it 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 +SIG, KEY and NXT 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, +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.2.4rc7/bin/rndc/include/rndc/os.h b/contrib/bind-9.2.4rc7/bin/rndc/include/rndc/os.h new file mode 100644 index 0000000000..8e3d2e7155 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/rndc/include/rndc/os.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001 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: os.h,v 1.4.2.1 2004/03/09 06:09:28 marka Exp $ */ + +#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 refernced 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.2.4rc7/bin/rndc/rndc-confgen.8 b/contrib/bind-9.2.4rc7/bin/rndc/rndc-confgen.8 new file mode 100644 index 0000000000..3e27d410c9 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/rndc/rndc-confgen.8 @@ -0,0 +1,130 @@ +.\" Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2001-2003 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: rndc-confgen.8,v 1.3.2.8 2004/06/03 05:21:14 marka Exp $ +.\" +.TH "RNDC-CONFGEN" "8" "Aug 27, 2001" "BIND9" "" +.SH NAME +rndc-confgen \- rndc key generation tool +.SH SYNOPSIS +.sp +\fBrndc-confgen\fR [ \fB-a\fR ] [ \fB-b \fIkeysize\fB\fR ] [ \fB-c \fIkeyfile\fB\fR ] [ \fB-h\fR ] [ \fB-k \fIkeyname\fB\fR ] [ \fB-p \fIport\fB\fR ] [ \fB-r \fIrandomfile\fB\fR ] [ \fB-s \fIaddress\fB\fR ] [ \fB-t \fIchrootdir\fB\fR ] [ \fB-u \fIuser\fB\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" +.TP +\fB-a\fR +Do automatic \fBrndc\fR configuration. +This creates a file \fIrndc.key\fR +in \fI/etc\fR (or whatever +sysconfdir +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 with no further configuration. + +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. +.TP +\fB-b \fIkeysize\fB\fR +Specifies the size of the authentication key in bits. +Must be between 1 and 512 bits; the default is 128. +.TP +\fB-c \fIkeyfile\fB\fR +Used with the \fB-a\fR option to specify +an alternate location for \fIrndc.key\fR. +.TP +\fB-h\fR +Prints a short summary of the options and arguments to +\fBrndc-confgen\fR. +.TP +\fB-k \fIkeyname\fB\fR +Specifies the key name of the rndc authentication key. +This must be a valid domain name. +The default is rndc-key. +.TP +\fB-p \fIport\fB\fR +Specifies the command channel port where \fBnamed\fR +listens for connections from \fBrndc\fR. +The default is 953. +.TP +\fB-r \fIrandomfile\fB\fR +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. +.TP +\fB-s \fIaddress\fB\fR +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. +.TP +\fB-t \fIchrootdir\fB\fR +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. +.TP +\fB-u \fIuser\fB\fR +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. +.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), +\fIBIND 9 Administrator Reference Manual\fR. +.SH "AUTHOR" +.PP +Internet Systems Consortium diff --git a/contrib/bind-9.2.4rc7/bin/rndc/rndc-confgen.c b/contrib/bind-9.2.4rc7/bin/rndc/rndc-confgen.c new file mode 100644 index 0000000000..29fd11e897 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/rndc/rndc-confgen.c @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001, 2003 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: rndc-confgen.c,v 1.9.2.7 2004/03/09 06:09:26 marka Exp $ */ + +#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]; +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); +} + +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; + + 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 = 1; + 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 '?': + usage(1); + break; + default: + fatal("unexpected error parsing command arguments: " + "got %c\n", ch); + break; + } + } + + 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", chrootdir, 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.2.4rc7/bin/rndc/rndc-confgen.html b/contrib/bind-9.2.4rc7/bin/rndc/rndc-confgen.html new file mode 100644 index 0000000000..2b08a18d81 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/rndc/rndc-confgen.html @@ -0,0 +1,548 @@ + + + + +rndc-confgen

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 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. +

-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.2.4rc7/bin/rndc/rndc.8 b/contrib/bind-9.2.4rc7/bin/rndc/rndc.8 new file mode 100644 index 0000000000..91bc9138d3 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/rndc/rndc.8 @@ -0,0 +1,118 @@ +.\" Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2000, 2001 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: rndc.8,v 1.24.2.2 2004/06/03 05:21:15 marka Exp $ +.\" +.TH "RNDC" "8" "June 30, 2000" "BIND9" "" +.SH NAME +rndc \- name server control utility +.SH SYNOPSIS +.sp +\fBrndc\fR [ \fB-c \fIconfig-file\fB\fR ] [ \fB-k \fIkey-file\fB\fR ] [ \fB-s \fIserver\fB\fR ] [ \fB-p \fIport\fB\fR ] [ \fB-V\fR ] [ \fB-y \fIkey_id\fB\fR ] \fBcommand\fR +.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 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. +.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" +.TP +\fB-c \fIconfig-file\fB\fR +Use \fIconfig-file\fR +as the configuration file instead of the default, +\fI/etc/rndc.conf\fR. +.TP +\fB-k \fIkey-file\fB\fR +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. +.TP +\fB-s \fIserver\fB\fR +\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 option statement of the configuration file will be +used. +.TP +\fB-p \fIport\fB\fR +Send commands to TCP port +\fIport\fR instead +of BIND 9's default control channel port, 953. +.TP +\fB-V\fR +Enable verbose logging. +.TP +\fB-y \fIkeyid\fB\fR +Use the key \fIkeyid\fR +from the configuration file. +\fIkeyid\fR must be +known by named with the same algorithm and secret string +in order for control message validation to succeed. +If no \fIkeyid\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. +.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. +.PP +.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), +\fBnamed\fR(8), +\fBnamed.conf\fR(5) +\fBndc\fR(8), +\fIBIND 9 Administrator Reference Manual\fR. +.SH "AUTHOR" +.PP +Internet Systems Consortium diff --git a/contrib/bind-9.2.4rc7/bin/rndc/rndc.c b/contrib/bind-9.2.4rc7/bin/rndc/rndc.c new file mode 100644 index 0000000000..071b8ac4c7 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/rndc/rndc.c @@ -0,0 +1,715 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001, 2003 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: rndc.c,v 1.77.2.6 2004/03/09 06:09:27 marka Exp $ */ + +/* + * 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 "util.h" + +#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 + +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 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 +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\ + reconfig Reload configuration file and new zones only.\n\ + stats Write server statistics to the statistics file.\n\ + querylog Toggle query logging.\n\ + dumpdb Dump cache(s) to the dump file (named_dump.db).\n\ + stop Save pending updates to master files and stop the server.\n\ + halt Stop the server without saving pending updates.\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\ + status Display status of the server.\n\ + *restart Restart the server.\n\ +\n\ +* == not yet implemented\n\ +Version: %s\n", + progname, version); + + exit(status); +} + +static void +get_address(const char *host, in_port_t port, isc_sockaddr_t *sockaddr) { + struct in_addr in4; + struct in6_addr in6; + isc_boolean_t have_ipv6; +#ifdef USE_GETADDRINFO + struct addrinfo *res = NULL, hints; + int result; +#else + struct hostent *he; +#endif + + have_ipv6 = ISC_TF(isc_net_probeipv6() == ISC_R_SUCCESS); + + /* + * Assume we have v4 if we don't have v6, since setup_libs + * fatal()'s out if we don't have either. + */ + if (have_ipv6 && inet_pton(AF_INET6, host, &in6) == 1) + isc_sockaddr_fromin6(sockaddr, &in6, port); + else if (inet_pton(AF_INET, host, &in4) == 1) + isc_sockaddr_fromin(sockaddr, &in4, port); + else { +#ifdef USE_GETADDRINFO + memset(&hints, 0, sizeof(hints)); + if (!have_ipv6) + hints.ai_family = PF_INET; + else if (isc_net_probeipv4() != ISC_R_SUCCESS) + hints.ai_family = PF_INET6; + else { + hints.ai_family = PF_UNSPEC; +#ifdef AI_ADDRCONFIG + hints.ai_flags = AI_ADDRCONFIG; +#endif + } + hints.ai_socktype = SOCK_STREAM; + isc_app_block(); +#ifdef AI_ADDRCONFIG + again: +#endif + result = getaddrinfo(host, NULL, &hints, &res); +#ifdef AI_ADDRCONFIG + if (result == EAI_BADFLAGS && + (hints.ai_flags & AI_ADDRCONFIG) != 0) { + hints.ai_flags &= ~AI_ADDRCONFIG; + goto again; + } +#endif + isc_app_unblock(); + if (result != 0) + fatal("Couldn't find server '%s': %s", + host, gai_strerror(result)); + memcpy(&sockaddr->type.sa, res->ai_addr, res->ai_addrlen); + sockaddr->length = res->ai_addrlen; + isc_sockaddr_setport(sockaddr, port); + freeaddrinfo(res); +#else + isc_app_block(); + he = gethostbyname(host); + isc_app_unblock(); + if (he == NULL) + fatal("Couldn't find server '%s' (h_errno=%d)", + host, h_errno); + INSIST(he->h_addrtype == AF_INET); + isc_sockaddr_fromin(sockaddr, + (struct in_addr *)(he->h_addr_list[0]), + port); +#endif + } +} + +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); +} + +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 the remote server is using " + "an older version of \n" + "the command protocol, this host is not authorized " + "to connect,\nor 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); + isc_socket_detach(&sock); + isc_task_shutdown(task); + isc_app_shutdown(); +} + +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 the remote server is using " + "an older version of \n" + "the command protocol, this host is not authorized " + "to connect,\nor 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) { + 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) + fatal("connect failed: %s", 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); + + 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_start(isc_task_t *task, isc_event_t *event) { + isc_sockaddr_t addr; + isc_result_t result; + char socktext[ISC_SOCKADDR_FORMATSIZE]; + + isc_event_free(&event); + + get_address(servername, (in_port_t) remoteport, &addr); + + isc_sockaddr_format(&addr, socktext, sizeof(socktext)); + + notify("using server %s (%s)", servername, socktext); + + DO("create socket", isc_socket_create(socketmgr, + isc_sockaddr_pf(&addr), + isc_sockettype_tcp, &sock)); + DO("connect", isc_socket_connect(sock, &addr, task, rndc_connected, + NULL)); + connects++; +} + +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; + cfg_obj_t *defkey = NULL; + cfg_obj_t *options = NULL; + cfg_obj_t *servers = NULL; + cfg_obj_t *server = NULL; + cfg_obj_t *keys = NULL; + cfg_obj_t *key = NULL; + cfg_obj_t *defport = NULL; + cfg_obj_t *secretobj = NULL; + cfg_obj_t *algorithmobj = NULL; + cfg_obj_t *config = NULL; + 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; + + 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) { + 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) { + 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) + cfg_map_get(options, "default-port", &defport); + } + if (defport != NULL) { + remoteport = cfg_obj_asuint32(defport); + if (remoteport > 65535 || remoteport == 0) + fatal("port %d out of range", remoteport); + } else if (remoteport == 0) + remoteport = NS_CONTROL_PORT; + + *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; + 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_app_start(); + + while ((ch = isc_commandline_parse(argc, argv, "c:k:Mmp:s:Vy:")) + != -1) { + switch (ch) { + case 'c': + admin_conffile = isc_commandline_argument; + break; + + case 'k': + admin_keyfile = isc_commandline_argument; + break; + + case 'M': + isc_mem_debugging = 1; + 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 '?': + usage(0); + break; + default: + fatal("unexpected error parsing command arguments: " + "got %c\n", ch); + break; + } + } + + 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); + + DO("post event", isc_app_onrun(mctx, task, rndc_start, NULL)); + + isc_app_run(); + + 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); + + 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.2.4rc7/bin/rndc/rndc.conf b/contrib/bind-9.2.4rc7/bin/rndc/rndc.conf new file mode 100644 index 0000000000..69ffa50121 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/rndc/rndc.conf @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 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: rndc.conf,v 1.7.2.1 2004/03/09 06:09:27 marka Exp $ */ + +/* + * Sample rndc configuration file. + */ + +options { + default-server localhost; + default-key "key"; +}; + +server localhost { + key "key"; +}; + +key "key" { + algorithm hmac-md5; + secret "c3Ryb25nIGVub3VnaCBmb3IgYSBtYW4gYnV0IG1hZGUgZm9yIGEgd29tYW4K"; +}; diff --git a/contrib/bind-9.2.4rc7/bin/rndc/rndc.conf.5 b/contrib/bind-9.2.4rc7/bin/rndc/rndc.conf.5 new file mode 100644 index 0000000000..7b9f3bebe5 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/rndc/rndc.conf.5 @@ -0,0 +1,142 @@ +.\" Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2000, 2001 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: rndc.conf.5,v 1.21.2.2 2004/06/03 05:21:15 marka Exp $ +.\" +.TH "RNDC.CONF" "5" "June 30, 2000" "BIND9" "" +.SH NAME +rndc.conf \- rndc configuration file +.SH SYNOPSIS +.sp +\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 three 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. +.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 two possible clauses: +\fBkey\fR and \fBport\fR. The key name must +match the name of a key statement in the file. The port number +specifies the port to connect to. +.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" +.sp +.nf + options { + default-server localhost; + default-key samplekey; + }; + + server localhost { + key samplekey; + }; + + key samplekey { + algorithm hmac-md5; + secret "c3Ryb25nIGVub3VnaCBmb3IgYSBtYW4gYnV0IG1hZGUgZm9yIGEgd29tYW4K"; + }; + +.sp +.fi +.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 +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), +\fIBIND 9 Administrator Reference Manual\fR. +.SH "AUTHOR" +.PP +Internet Systems Consortium diff --git a/contrib/bind-9.2.4rc7/bin/rndc/rndc.conf.html b/contrib/bind-9.2.4rc7/bin/rndc/rndc.conf.html new file mode 100644 index 0000000000..6bca52b2ee --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/rndc/rndc.conf.html @@ -0,0 +1,381 @@ + + + + +rndc.conf

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 three 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. +

After the server keyword, the server statement + includes a string which is the hostname or address for a name + server. The statement has two possible clauses: + key and port. The key name must + match the name of a key statement in the file. The port number + specifies the port to connect to. +

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;
+      };
+
+      key samplekey {
+        algorithm       hmac-md5;
+        secret          "c3Ryb25nIGVub3VnaCBmb3IgYSBtYW4gYnV0IG1hZGUgZm9yIGEgd29tYW4K";
+      };
+    

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. +

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.2.4rc7/bin/rndc/rndc.html b/contrib/bind-9.2.4rc7/bin/rndc/rndc.html new file mode 100644 index 0000000000..d133cb2867 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/rndc/rndc.html @@ -0,0 +1,424 @@ + + + + +rndc

rndc

Name

rndc -- name server control utility

Synopsis

rndc [-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 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

-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 option statement of the 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 keyid

Use the key keyid + from the configuration file. + keyid must be + known by named with the same algorithm and secret string + in order for control message validation to succeed. + If no keyid + 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), + named(8), + named.conf(5) + ndc(8), + BIND 9 Administrator Reference Manual. +

AUTHOR

Internet Systems Consortium +

diff --git a/contrib/bind-9.2.4rc7/bin/rndc/unix/os.c b/contrib/bind-9.2.4rc7/bin/rndc/unix/os.c new file mode 100644 index 0000000000..2278bc23d5 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/rndc/unix/os.c @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001 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: os.c,v 1.5.2.1 2004/03/09 06:09:28 marka Exp $ */ + +#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.2.4rc7/bin/rndc/util.c b/contrib/bind-9.2.4rc7/bin/rndc/util.c new file mode 100644 index 0000000000..fe495d274e --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/rndc/util.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 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: util.c,v 1.2.2.1 2004/03/09 06:09:27 marka Exp $ */ + +#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.2.4rc7/bin/rndc/util.h b/contrib/bind-9.2.4rc7/bin/rndc/util.h new file mode 100644 index 0000000000..43d6cb2350 --- /dev/null +++ b/contrib/bind-9.2.4rc7/bin/rndc/util.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 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: util.h,v 1.5.2.1 2004/03/09 06:09:27 marka Exp $ */ + +#ifndef RNDC_UTIL_H +#define RNDC_UTIL_H 1 + +#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.2.4rc7/lib/bind/README b/contrib/bind-9.2.4rc7/lib/bind/README new file mode 100644 index 0000000000..b89cff7095 --- /dev/null +++ b/contrib/bind-9.2.4rc7/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.2.4rc7/lib/bind/api b/contrib/bind-9.2.4rc7/lib/bind/api new file mode 100644 index 0000000000..0ca3d9e7f7 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/api @@ -0,0 +1,3 @@ +LIBINTERFACE = 3 +LIBREVISION = 6 +LIBAGE = 0 diff --git a/contrib/bind-9.2.4rc7/lib/bind/bsd/daemon.c b/contrib/bind-9.2.4rc7/lib/bind/bsd/daemon.c new file mode 100644 index 0000000000..a1472f969b --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/bsd/daemon.c @@ -0,0 +1,79 @@ +#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.1 2001/03/29 06:30:31 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 "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 diff --git a/contrib/bind-9.2.4rc7/lib/bind/bsd/ftruncate.c b/contrib/bind-9.2.4rc7/lib/bind/bsd/ftruncate.c new file mode 100644 index 0000000000..56ce8d34a9 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/bsd/ftruncate.c @@ -0,0 +1,63 @@ +#ifndef LINT +static const char rcsid[] = "$Id: ftruncate.c,v 1.1 2001/03/29 06:30:32 marka Exp $"; +#endif + +/* + * 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.2.4rc7/lib/bind/bsd/gettimeofday.c b/contrib/bind-9.2.4rc7/lib/bind/bsd/gettimeofday.c new file mode 100644 index 0000000000..ffde020213 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/bsd/gettimeofday.c @@ -0,0 +1,62 @@ +#ifndef LINT +static const char rcsid[] = "$Id: gettimeofday.c,v 1.1.2.2 2002/07/12 00:49:51 marka 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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/bsd/mktemp.c b/contrib/bind-9.2.4rc7/lib/bind/bsd/mktemp.c new file mode 100644 index 0000000000..9852a356ac --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/bsd/mktemp.c @@ -0,0 +1,154 @@ +#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.1 2001/03/29 06:30:33 marka 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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/bsd/putenv.c b/contrib/bind-9.2.4rc7/lib/bind/bsd/putenv.c new file mode 100644 index 0000000000..abaa525d36 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/bsd/putenv.c @@ -0,0 +1,25 @@ +#ifndef LINT +static const char rcsid[] = "$Id: putenv.c,v 1.1 2001/03/29 06:30:33 marka 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 diff --git a/contrib/bind-9.2.4rc7/lib/bind/bsd/readv.c b/contrib/bind-9.2.4rc7/lib/bind/bsd/readv.c new file mode 100644 index 0000000000..ccfcb5af33 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/bsd/readv.c @@ -0,0 +1,38 @@ +#ifndef LINT +static const char rcsid[] = "$Id: readv.c,v 1.1 2001/03/29 06:30:35 marka 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 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/bsd/setenv.c b/contrib/bind-9.2.4rc7/lib/bind/bsd/setenv.c new file mode 100644 index 0000000000..6a11c9db82 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/bsd/setenv.c @@ -0,0 +1,149 @@ +#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.1 2001/03/29 06:30:35 marka 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 diff --git a/contrib/bind-9.2.4rc7/lib/bind/bsd/setitimer.c b/contrib/bind-9.2.4rc7/lib/bind/bsd/setitimer.c new file mode 100644 index 0000000000..791846a299 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/bsd/setitimer.c @@ -0,0 +1,27 @@ +#ifndef LINT +static const char rcsid[] = "$Id: setitimer.c,v 1.1 2001/03/29 06:30:35 marka 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 diff --git a/contrib/bind-9.2.4rc7/lib/bind/bsd/strcasecmp.c b/contrib/bind-9.2.4rc7/lib/bind/bsd/strcasecmp.c new file mode 100644 index 0000000000..c8c9d056bb --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/bsd/strcasecmp.c @@ -0,0 +1,122 @@ +#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.1 2001/03/29 06:30:35 marka 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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/bsd/strdup.c b/contrib/bind-9.2.4rc7/lib/bind/bsd/strdup.c new file mode 100644 index 0000000000..246bc1f49f --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/bsd/strdup.c @@ -0,0 +1,18 @@ +#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 diff --git a/contrib/bind-9.2.4rc7/lib/bind/bsd/strerror.c b/contrib/bind-9.2.4rc7/lib/bind/bsd/strerror.c new file mode 100644 index 0000000000..d13adbb03b --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/bsd/strerror.c @@ -0,0 +1,90 @@ +#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.3.2.1 2001/11/02 17:45:31 gson 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; + const char *ret; + char tmp[40]; + + errnum = num; /* convert to unsigned */ +#ifdef USE_SYSERROR_LIST + if (errnum < 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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/bsd/strpbrk.c b/contrib/bind-9.2.4rc7/lib/bind/bsd/strpbrk.c new file mode 100644 index 0000000000..ff039e1594 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/bsd/strpbrk.c @@ -0,0 +1,68 @@ +#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.1 2001/03/29 06:30:36 marka 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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/bsd/strsep.c b/contrib/bind-9.2.4rc7/lib/bind/bsd/strsep.c new file mode 100644 index 0000000000..3dcee4aab8 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/bsd/strsep.c @@ -0,0 +1,86 @@ +#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.1 2001/03/29 06:30:36 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 "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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/bsd/strtoul.c b/contrib/bind-9.2.4rc7/lib/bind/bsd/strtoul.c new file mode 100644 index 0000000000..d110f30943 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/bsd/strtoul.c @@ -0,0 +1,117 @@ +#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.1.2.1 2003/06/27 03:51:35 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 = *(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 = *(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) + *endptr = (char *)(any ? s - 1 : nptr); + return (acc); +} + +#endif /*NEED_STRTOUL*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/bsd/utimes.c b/contrib/bind-9.2.4rc7/lib/bind/bsd/utimes.c new file mode 100644 index 0000000000..6a288f4956 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/bsd/utimes.c @@ -0,0 +1,39 @@ +/* + * 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 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/bsd/writev.c b/contrib/bind-9.2.4rc7/lib/bind/bsd/writev.c new file mode 100644 index 0000000000..fe204a97ae --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/bsd/writev.c @@ -0,0 +1,87 @@ +#ifndef LINT +static const char rcsid[] = "$Id: writev.c,v 1.1.2.1 2003/06/27 03:51:35 marka 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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/config.h.in b/contrib/bind-9.2.4rc7/lib/bind/config.h.in new file mode 100644 index 0000000000..46de822b7e --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/config.h.in @@ -0,0 +1,45 @@ +#undef _SOCKADDR_LEN +#undef HAVE_FCNTL_H +#undef HAVE_PATHS_H +#undef HAVE_SYS_TIMERS_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 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 + +/* 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 diff --git a/contrib/bind-9.2.4rc7/lib/bind/dst/dst_api.c b/contrib/bind-9.2.4rc7/lib/bind/dst/dst_api.c new file mode 100644 index 0000000000..9b78738938 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/dst/dst_api.c @@ -0,0 +1,1048 @@ +#ifndef LINT +static const char rcsid[] = "$Header: /proj/cvs/prod/bind9/lib/bind/dst/dst_api.c,v 1.4.2.6 2002/07/12 00:17:19 marka 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); + 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 + 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); + + pubkey = 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: + * Kdk_name>+dk_alg>+dk_id>.. + * 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)); + 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. 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, 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 ((key_st = dst_s_get_key_struct(in_name, alg, 0, 0, 0)) == NULL) + return (NULL); + + if (in_name == 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) + return (NULL); + if (dkey->dk_func == NULL || dkey->dk_func->from_dns_key == NULL) + return NULL; + + 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 **) &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 **) &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); +} + + +/* + * dst_generate_key + * Generate and store a public/private keypair. + * Keys will be stored in formatted files. + * Parameters + * name Name of the new key. Used to create key files + * K++.public and K++.private. + * bits Size of the new key in bits. + * exp What exponent to use: + * 0 use exponent 3 + * non-zero use Fermant4 + * flags The default value of the DNS Key flags. + * The DNS Key RR Flag field is defined in RFC 2065, + * section 3.3. The field has 16 bits. + * protocol + * Default value of the DNS Key protocol field. + * The DNS Key protocol field is defined in RFC 2065, + * section 3.4. The field has 8 bits. + * alg What algorithm to use. Currently defined: + * KEY_RSA 1 + * KEY_DSA 3 + * KEY_HMAC 157 + * out_id The key tag is returned. + * + * Return + * NULL Failure + * 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 res; + 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 ((res = 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); +} + + +/* + * dst_free_key + * Release all data structures pointed to by a key structure. + * Parameters + * 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)); + free(f_key->dk_KEY_struct); /* SHOULD NOT happen */ + } + 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); +} + +/* + * dst_sig_size + * Return the maximim size of signature from the key specified in bytes + * Parameters + * key + * Returns + * 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; + } +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/dst/dst_internal.h b/contrib/bind-9.2.4rc7/lib/bind/dst/dst_internal.h new file mode 100644 index 0000000000..928650a726 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/dst/dst_internal.h @@ -0,0 +1,154 @@ +#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 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/dst/hmac_link.c b/contrib/bind-9.2.4rc7/lib/bind/dst/hmac_link.c new file mode 100644 index 0000000000..8a641d0bf9 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/dst/hmac_link.c @@ -0,0 +1,468 @@ +#ifdef HMAC_MD5 +#ifndef LINT +static const char rcsid[] = "$Header: /proj/cvs/prod/bind9/lib/bind/dst/hmac_link.c,v 1.2.2.1 2003/06/27 03:51:36 marka 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 +# include "md5.h" +# 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 (mode & SIG_MODE_INIT) + ctx = (MD5_CTX *) malloc(sizeof(*ctx)); + else if (context) + ctx = (MD5_CTX *) *context; + if (ctx == NULL) + return (-1); + + if (d_key == NULL || d_key->dk_KEY_struct == 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 (mode & SIG_MODE_INIT) + ctx = (MD5_CTX *) malloc(sizeof(*ctx)); + else if (context) + ctx = (MD5_CTX *) *context; + if (ctx == NULL) + return (-1); + + if (d_key == NULL || d_key->dk_KEY_struct == 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; + + 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) { + u_char tk[MD5_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, b_len, i, key_len; + u_char key[HMAC_LEN]; + HMAC_Key *hkey; + + if (dkey == NULL || dkey->dk_KEY_struct == NULL) + return (0); + if (buff == NULL || buff_len <= (int) strlen(key_file_fmt_str)) + 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 = (char *) strchr(buff, '\0'); + b_len = buff_len - (bp - 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; + + strcat(bp, "Key: "); + bp += strlen("Key: "); + b_len = buff_len - (bp - buff); + + len = b64_ntop(key, key_len, bp, b_len); + if (len < 0) + return (-1); + bp += len; + *(bp++) = '\n'; + *bp = '\0'; + b_len = buff_len - (bp - buff); + + return (buff_len - b_len); +} + + +/************************************************************************** + * 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); + 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 +dst_hmac_md5_init() +{ + 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 diff --git a/contrib/bind-9.2.4rc7/lib/bind/dst/md5.h b/contrib/bind-9.2.4rc7/lib/bind/dst/md5.h new file mode 100644 index 0000000000..c886d17bb0 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/dst/md5.h @@ -0,0 +1,101 @@ +/* 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 + +#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 diff --git a/contrib/bind-9.2.4rc7/lib/bind/dst/md5_dgst.c b/contrib/bind-9.2.4rc7/lib/bind/dst/md5_dgst.c new file mode 100644 index 0000000000..48c327eac3 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/dst/md5_dgst.c @@ -0,0 +1,370 @@ +/* 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 +#include +#include "md5_locl.h" +#include + +const char *MD5_version="MD5 part of SSLeay 0.8.1 19-Jul-1997"; + +/* 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 /* USE_MD5 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/dst/md5_locl.h b/contrib/bind-9.2.4rc7/lib/bind/dst/md5_locl.h new file mode 100644 index 0000000000..ce4c765c1b --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/dst/md5_locl.h @@ -0,0 +1,190 @@ +/* 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; }; diff --git a/contrib/bind-9.2.4rc7/lib/bind/dst/support.c b/contrib/bind-9.2.4rc7/lib/bind/dst/support.c new file mode 100644 index 0000000000..7b86ea98d3 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/dst/support.c @@ -0,0 +1,350 @@ +static const char rcsid[] = "$Header: /proj/cvs/prod/bind9/lib/bind/dst/support.c,v 1.2.2.1 2001/11/02 22:25:29 gson 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 (-1); + + 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++. + * + * 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. + * form: K++. + * + * 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]; + size_t plen = sizeof(pathname); + + if (*dst_path != '\0') { + strcpy(pathname, dst_path); + plen -= strlen(pathname); + } + else + pathname[0] = '\0'; + + if (plen > strlen(filename)) + strncpy(&pathname[PATH_MAX - plen], filename, plen-1); + else + return (NULL); + + 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 + } +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/include/arpa/inet.h b/contrib/bind-9.2.4rc7/lib/bind/include/arpa/inet.h new file mode 100644 index 0000000000..e5b4c34a83 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/include/arpa/inet.h @@ -0,0 +1,124 @@ +/* + * ++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.1.2.1 2004/03/09 09:17:24 marka 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_ */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/include/arpa/nameser.h b/contrib/bind-9.2.4rc7/lib/bind/include/arpa/nameser.h new file mode 100644 index 0000000000..d5cd4fce37 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/include/arpa/nameser.h @@ -0,0 +1,576 @@ +/* + * 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.2.2.5 2004/03/09 09:17:25 marka Exp $ + */ + +#ifndef _ARPA_NAMESER_H_ +#define _ARPA_NAMESER_H_ + +#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 RFC 883, RFC 1034, 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 (RFC 3123) */ + 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, host order. + */ +#define NS_OPT_DNSSEC_OK 0x8000U + +/* + * 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_ */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/include/arpa/nameser_compat.h b/contrib/bind-9.2.4rc7/lib/bind/include/arpa/nameser_compat.h new file mode 100644 index 0000000000..9eabb16cce --- /dev/null +++ b/contrib/bind-9.2.4rc7/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.1.2.5 2004/07/01 04:42:04 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(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_ */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/include/fd_setsize.h b/contrib/bind-9.2.4rc7/lib/bind/include/fd_setsize.h new file mode 100644 index 0000000000..235b1ad1c2 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/include/fd_setsize.h @@ -0,0 +1,9 @@ +#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 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/include/hesiod.h b/contrib/bind-9.2.4rc7/lib/bind/include/hesiod.h new file mode 100644 index 0000000000..d8297b4a1c --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/include/hesiod.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +/* + * This file is primarily maintained by and . + */ + +/* + * $Id: hesiod.h,v 1.1.2.2 2004/03/09 09:17:24 marka 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.2.4rc7/lib/bind/include/irp.h b/contrib/bind-9.2.4rc7/lib/bind/include/irp.h new file mode 100644 index 0000000000..8246fff8a1 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/include/irp.h @@ -0,0 +1,103 @@ +/* + * 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.1.2.2 2004/03/09 09:17:24 marka Exp $ + */ + +#ifndef _IRP_H_INCLUDED +#define _IRP_H_INCLUDED + +#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 diff --git a/contrib/bind-9.2.4rc7/lib/bind/include/irs.h b/contrib/bind-9.2.4rc7/lib/bind/include/irs.h new file mode 100644 index 0000000000..00d3da2cfa --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/include/irs.h @@ -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. + */ + +/* + * $Id: irs.h,v 1.2.2.2 2004/03/09 09:17:24 marka Exp $ + */ + +#ifndef _IRS_H_INCLUDED +#define _IRS_H_INCLUDED + +#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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/include/isc/assertions.h b/contrib/bind-9.2.4rc7/lib/bind/include/isc/assertions.h new file mode 100644 index 0000000000..ca0268c569 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/include/isc/assertions.h @@ -0,0 +1,122 @@ +/* + * 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.1.2.1 2004/03/09 09:17:25 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); + +extern assertion_failure_callback __assertion_failed; +void set_assertion_failure_callback(assertion_failure_callback f); +const char *assertion_type_to_text(assertion_type type); + +#ifdef CHECK_ALL +#define CHECK_REQUIRE 1 +#define CHECK_ENSURE 1 +#define CHECK_INSIST 1 +#define CHECK_INVARIANT 1 +#endif + +#ifdef CHECK_NONE +#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 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/include/isc/ctl.h b/contrib/bind-9.2.4rc7/lib/bind/include/isc/ctl.h new file mode 100644 index 0000000000..cd7f7f70e6 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/include/isc/ctl.h @@ -0,0 +1,109 @@ +#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.1.2.3 2004/03/09 09:17:25 marka Exp $ + */ + +#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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/include/isc/dst.h b/contrib/bind-9.2.4rc7/lib/bind/include/isc/dst.h new file mode 100644 index 0000000000..fe9229725a --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/include/isc/dst.h @@ -0,0 +1,180 @@ +#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 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/include/isc/eventlib.h b/contrib/bind-9.2.4rc7/lib/bind/include/isc/eventlib.h new file mode 100644 index 0000000000..079c262592 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/include/isc/eventlib.h @@ -0,0 +1,200 @@ +/* + * 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.1.2.2 2004/03/09 09:17:25 marka Exp $ + */ + +#ifndef _EVENTLIB_H +#define _EVENTLIB_H + +#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 + +/* 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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/include/isc/heap.h b/contrib/bind-9.2.4rc7/lib/bind/include/isc/heap.h new file mode 100644 index 0000000000..691c821d1e --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/include/isc/heap.h @@ -0,0 +1,47 @@ +/* + * 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 *); diff --git a/contrib/bind-9.2.4rc7/lib/bind/include/isc/irpmarshall.h b/contrib/bind-9.2.4rc7/lib/bind/include/isc/irpmarshall.h new file mode 100644 index 0000000000..2da3952b95 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/include/isc/irpmarshall.h @@ -0,0 +1,115 @@ +/* + * 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.1.2.2 2004/03/09 09:17:26 marka 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 *); + +/* + * 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.2.4rc7/lib/bind/include/isc/list.h b/contrib/bind-9.2.4rc7/lib/bind/include/isc/list.h new file mode 100644 index 0000000000..ad574ac2b5 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/include/isc/list.h @@ -0,0 +1,112 @@ +/* + * 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 \ + (list).tail = (elt)->link.prev; \ + if ((elt)->link.prev != NULL) \ + (elt)->link.prev->link.next = (elt)->link.next; \ + else \ + (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 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/include/isc/logging.h b/contrib/bind-9.2.4rc7/lib/bind/include/isc/logging.h new file mode 100644 index 0000000000..574fd8a257 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/include/isc/logging.h @@ -0,0 +1,112 @@ +/* + * 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 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/include/isc/memcluster.h b/contrib/bind-9.2.4rc7/lib/bind/include/isc/memcluster.h new file mode 100644 index 0000000000..11e1fa381d --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/include/isc/memcluster.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. + */ + +#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 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/include/isc/misc.h b/contrib/bind-9.2.4rc7/lib/bind/include/isc/misc.h new file mode 100644 index 0000000000..a597e1fa8e --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/include/isc/misc.h @@ -0,0 +1,39 @@ +/* + * 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.2.2.2 2004/03/09 09:17:26 marka Exp $ + */ + +#ifndef _ISC_MISC_H +#define _ISC_MISC_H + +#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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/include/isc/tree.h b/contrib/bind-9.2.4rc7/lib/bind/include/isc/tree.h new file mode 100644 index 0000000000..0572c407c8 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/include/isc/tree.h @@ -0,0 +1,58 @@ +/* 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.1.2.1 2003/06/27 03:51:39 marka 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 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/include/netdb.h b/contrib/bind-9.2.4rc7/lib/bind/include/netdb.h new file mode 100644 index 0000000000..59abd0400c --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/include/netdb.h @@ -0,0 +1,549 @@ +/* + * ++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.12.2.5 2004/03/16 02:25:06 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 __sparc9 + 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; +#ifdef __osf__ + 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 +}; + +struct protoent_data { + FILE *proto_fp; +#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 +}; + +struct servent_data { + FILE *serv_fp; +#ifdef __osf__ + 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 +}; +#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 +#else + /* defined(sun) || defined(bsdi) */ +#ifdef __GLIBC__ +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)); + +#ifdef __GLIBC__ +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)); + +#ifdef __GLIBC__ +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)); + +#ifdef __GLIBC__ +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_ */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/include/netgroup.h b/contrib/bind-9.2.4rc7/lib/bind/include/netgroup.h new file mode 100644 index 0000000000..2296208c15 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/include/netgroup.h @@ -0,0 +1,24 @@ +#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 diff --git a/contrib/bind-9.2.4rc7/lib/bind/include/res_update.h b/contrib/bind-9.2.4rc7/lib/bind/include/res_update.h new file mode 100644 index 0000000000..5392573646 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/include/res_update.h @@ -0,0 +1,65 @@ +/* + * 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.1.2.1 2004/03/09 09:17:24 marka Exp $ + */ + +#ifndef __RES_UPDATE_H +#define __RES_UPDATE_H + +#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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/include/resolv.h b/contrib/bind-9.2.4rc7/lib/bind/include/resolv.h new file mode 100644 index 0000000000..b8339c4c5d --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/include/resolv.h @@ -0,0 +1,501 @@ +/* + * 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.7.2.13 2004/06/25 00:39:31 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_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 +#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_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)); +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_ */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/inet/inet_addr.c b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_addr.c new file mode 100644 index 0000000000..f6867fa028 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_addr.c @@ -0,0 +1,206 @@ +/* + * 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.2.2.2 2004/03/17 00:40:10 marka 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/inet/inet_cidr_ntop.c b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_cidr_ntop.c new file mode 100644 index 0000000000..126fc9c896 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_cidr_ntop.c @@ -0,0 +1,259 @@ +/* + * 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.1.2.3 2004/03/17 00:40:10 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 __P((const u_char *src, int bits, + char *dst, size_t size)); +static char * inet_cidr_ntop_ipv6 __P((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; + cur.base = -1; + 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/inet/inet_cidr_pton.c b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_cidr_pton.c new file mode 100644 index 0000000000..6fe5f7b03b --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_cidr_pton.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: inet_cidr_pton.c,v 1.2.2.3 2004/03/17 00:40:11 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_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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/inet/inet_data.c b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_data.c new file mode 100644 index 0000000000..cc086fe83c --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_data.c @@ -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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = "$Id: inet_data.c,v 1.2.2.1 2004/03/09 09:17:27 marka 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; diff --git a/contrib/bind-9.2.4rc7/lib/bind/inet/inet_lnaof.c b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_lnaof.c new file mode 100644 index 0000000000..97b80cffdb --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_lnaof.c @@ -0,0 +1,63 @@ +/* + * 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/inet/inet_makeaddr.c b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_makeaddr.c new file mode 100644 index 0000000000..1d20619b99 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_makeaddr.c @@ -0,0 +1,66 @@ +/* + * 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; +{ + u_long addr; + + if (net < 128U) + addr = (net << IN_CLASSA_NSHIFT) | (host & IN_CLASSA_HOST); + else if (net < 65536U) + addr = (net << IN_CLASSB_NSHIFT) | (host & IN_CLASSB_HOST); + else if (net < 16777216L) + addr = (net << IN_CLASSC_NSHIFT) | (host & IN_CLASSC_HOST); + else + addr = net | host; + addr = htonl(addr); + return (*(struct in_addr *)&addr); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/inet/inet_net_ntop.c b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_net_ntop.c new file mode 100644 index 0000000000..4d21ca9a67 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_net_ntop.c @@ -0,0 +1,277 @@ +/* + * 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.1.2.2 2004/03/09 09:17:27 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/inet/inet_net_pton.c b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_net_pton.c new file mode 100644 index 0000000000..44a6f92ce1 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_net_pton.c @@ -0,0 +1,405 @@ +/* + * 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.4.2.3 2004/03/17 00:40:11 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; + } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch)); + if (ch != '\0') + goto enoent; + if (bits > 32) + goto emsgsize; + } + + /* 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); + } +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/inet/inet_neta.c b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_neta.c new file mode 100644 index 0000000000..9b5a71a378 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_neta.c @@ -0,0 +1,87 @@ +/* + * 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.1.2.1 2004/03/09 09:17:27 marka 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/inet/inet_netof.c b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_netof.c new file mode 100644 index 0000000000..e887530088 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_netof.c @@ -0,0 +1,62 @@ +/* + * 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/inet/inet_network.c b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_network.c new file mode 100644 index 0000000000..aaa50c8315 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_network.c @@ -0,0 +1,104 @@ +/* + * 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 (*cp == '.') { + if (pp >= parts + 4 || val > 0xffU) + return (INADDR_NONE); + *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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/inet/inet_ntoa.c b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_ntoa.c new file mode 100644 index 0000000000..7fad4b8902 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_ntoa.c @@ -0,0 +1,62 @@ +/* + * 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.1 2001/03/29 06:31:38 marka 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/inet/inet_ntop.c b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_ntop.c new file mode 100644 index 0000000000..1f9adf3531 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_ntop.c @@ -0,0 +1,203 @@ +/* + * 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.1.2.2 2004/03/09 09:17:27 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; + cur.base = -1; + 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/inet/inet_pton.c b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_pton.c new file mode 100644 index 0000000000..076e61c403 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/inet/inet_pton.c @@ -0,0 +1,222 @@ +/* + * 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.2.2.1 2004/03/09 09:17:27 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, saw_xdigit; + 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; + saw_xdigit = 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 (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_pton4(curtok, tp) > 0) { + tp += NS_INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return (0); + } + if (saw_xdigit) { + 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/inet/nsap_addr.c b/contrib/bind-9.2.4rc7/lib/bind/inet/nsap_addr.c new file mode 100644 index 0000000000..77c2e9a3b9 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/inet/nsap_addr.c @@ -0,0 +1,108 @@ +/* + * 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.2.2.1 2004/03/09 09:17:27 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include "port_before.h" + +#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; + static char tmpbuf[2+255*3]; + 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/dns.c b/contrib/bind-9.2.4rc7/lib/bind/irs/dns.c new file mode 100644 index 0000000000..dbd3063479 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/dns.c @@ -0,0 +1,153 @@ +/* + * 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.1.2.2 2004/03/17 00:40:11 marka Exp $"; +#endif + +/* + * 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(dns->res, 0, sizeof *dns->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.2.4rc7/lib/bind/irs/dns_gr.c b/contrib/bind-9.2.4rc7/lib/bind/irs/dns_gr.c new file mode 100644 index 0000000000..18994b6dcf --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/dns_gr.c @@ -0,0 +1,293 @@ +/* + * 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.1.2.2 2004/03/09 09:17:28 marka Exp $"; +#endif + +/* + * 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.2.4rc7/lib/bind/irs/dns_ho.c b/contrib/bind-9.2.4rc7/lib/bind/irs/dns_ho.c new file mode 100644 index 0000000000..78eb0d8f62 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/dns_ho.c @@ -0,0 +1,1150 @@ +/* + * 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.5.2.11 2004/05/17 07:46:42 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); + if (pvt) + 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 ((qp - q->qname) + strlen(nibsuff2) + 1 > + sizeof q->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 && 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, arcount; + 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); + arcount = ntohs(hp->arcount); + 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]) { + had_error++; + continue; + } + if (ret_aip) { /* need addrinfo. keep it. */ + while (cur && 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-1]) + 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 && haveanswer > 1 && qtype == T_A) + addrsort(pvt->res, pvt->h_addr_ptrs, + haveanswer); + 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]) + return(-1); + if (hap >= &pvt->h_addr_ptrs[MAXADDRS-1]) + 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.2.4rc7/lib/bind/irs/dns_nw.c b/contrib/bind-9.2.4rc7/lib/bind/irs/dns_nw.c new file mode 100644 index 0000000000..106f50d1c4 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/dns_nw.c @@ -0,0 +1,589 @@ +/* + * 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.3.2.7 2004/05/17 07:46:42 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 "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); + + /* 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/dns_p.h b/contrib/bind-9.2.4rc7/lib/bind/irs/dns_p.h new file mode 100644 index 0000000000..54d1b14395 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/dns_p.h @@ -0,0 +1,50 @@ +/* + * 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.1.2.2 2004/03/17 00:40:12 marka 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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/dns_pr.c b/contrib/bind-9.2.4rc7/lib/bind/irs/dns_pr.c new file mode 100644 index 0000000000..12fc9d045a --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/dns_pr.c @@ -0,0 +1,266 @@ +/* + * 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.3.2.1 2004/03/09 09:17:28 marka 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/dns_pw.c b/contrib/bind-9.2.4rc7/lib/bind/irs/dns_pw.c new file mode 100644 index 0000000000..027947cabe --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/dns_pw.c @@ -0,0 +1,231 @@ +/* + * 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.1.2.1 2004/03/09 09:17:28 marka 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 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/dns_sv.c b/contrib/bind-9.2.4rc7/lib/bind/irs/dns_sv.c new file mode 100644 index 0000000000..4969807787 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/dns_sv.c @@ -0,0 +1,298 @@ +/* + * 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.3.2.1 2004/03/09 09:17:28 marka 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 diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/gai_strerror.c b/contrib/bind-9.2.4rc7/lib/bind/irs/gai_strerror.c new file mode 100644 index 0000000000..7355b93c3c --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/gai_strerror.c @@ -0,0 +1,86 @@ +/* + * 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 */ + static pthread_mutex_t lock = PTHREAD_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) { + pthread_mutex_lock(&lock); + if (!once++) + pthread_key_create(&key, free); + pthread_mutex_unlock(&lock); + } + + buf = pthread_getspecific(key); + if (buf == NULL) { + buf = malloc(EAI_BUFSIZE); + if (buf == NULL) + return ("unknown error"); + pthread_setspecific(key, buf); + } +#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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/gen.c b/contrib/bind-9.2.4rc7/lib/bind/irs/gen.c new file mode 100644 index 0000000000..d389803232 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/gen.c @@ -0,0 +1,430 @@ +/* + * 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.3.2.2 2004/03/17 00:40:12 marka Exp $"; +#endif + +/* + * 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, "%%%ds %%%ds %%%ds\n", + sizeof mapname, sizeof accname, 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.2.4rc7/lib/bind/irs/gen_gr.c b/contrib/bind-9.2.4rc7/lib/bind/irs/gen_gr.c new file mode 100644 index 0000000000..a97a56f20a --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/gen_gr.c @@ -0,0 +1,492 @@ +/* + * 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.4.2.3 2004/05/17 07:46:43 marka 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 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/gen_ho.c b/contrib/bind-9.2.4rc7/lib/bind/irs/gen_ho.c new file mode 100644 index 0000000000..eaad3313d1 --- /dev/null +++ b/contrib/bind-9.2.4rc7/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.1.2.2 2004/03/17 01:54:19 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); + if (rval) + freeaddrinfo(rval); + 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/gen_ng.c b/contrib/bind-9.2.4rc7/lib/bind/irs/gen_ng.c new file mode 100644 index 0000000000..11f7117974 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/gen_ng.c @@ -0,0 +1,172 @@ +/* + * 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.1.2.1 2004/03/09 09:17:29 marka 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); + } +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/gen_nw.c b/contrib/bind-9.2.4rc7/lib/bind/irs/gen_nw.c new file mode 100644 index 0000000000..96f4be5990 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/gen_nw.c @@ -0,0 +1,262 @@ +/* + * 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.1.2.2 2004/03/17 01:54:20 marka 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/gen_p.h b/contrib/bind-9.2.4rc7/lib/bind/irs/gen_p.h new file mode 100644 index 0000000000..5f908793ef --- /dev/null +++ b/contrib/bind-9.2.4rc7/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.1.2.1 2004/03/09 09:17:29 marka Exp $ + */ + +/* 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.2.4rc7/lib/bind/irs/gen_pr.c b/contrib/bind-9.2.4rc7/lib/bind/irs/gen_pr.c new file mode 100644 index 0000000000..d75a78bcda --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/gen_pr.c @@ -0,0 +1,226 @@ +/* + * 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.1.2.1 2004/03/09 09:17:29 marka 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); + } +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/gen_pw.c b/contrib/bind-9.2.4rc7/lib/bind/irs/gen_pw.c new file mode 100644 index 0000000000..a0c97a0c2f --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/gen_pw.c @@ -0,0 +1,233 @@ +/* + * 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.1.2.1 2004/03/09 09:17:29 marka 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 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/gen_sv.c b/contrib/bind-9.2.4rc7/lib/bind/irs/gen_sv.c new file mode 100644 index 0000000000..fbe8d5fa51 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/gen_sv.c @@ -0,0 +1,227 @@ +/* + * 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.1.2.1 2004/03/09 09:17:29 marka 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); + } +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/getaddrinfo.c b/contrib/bind-9.2.4rc7/lib/bind/irs/getaddrinfo.c new file mode 100644 index 0000000000..291fba1646 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/getaddrinfo.c @@ -0,0 +1,1226 @@ +/* $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. + */ + +/* + * Issues to be discussed: + * - Thread safe-ness must be checked. + * - 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. + * - 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). + * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is + * invalid. + * current code - SEGV on freeaddrinfo(NULL) + * Note: + * - 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(). + * - 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? + * - (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? + * - 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: + * - The code makes use of following calls when asked to resolver with + * ai_family = PF_UNSPEC: + * getipnodebyname(host, AF_INET6); + * getipnodebyname(host, AF_INET); + * This will result in the following queries if the node is configure to + * prefer /etc/hosts than DNS: + * lookup /etc/hosts for IPv6 address + * lookup DNS for IPv6 address + * lookup /etc/hosts for IPv4 address + * lookup DNS for IPv4 address + * which may not meet people's requirement. + * 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) + +#define ERR(err) \ +do { \ + /* external reference: error, and label bad */ \ + error = (err); \ + goto bad; \ + /*NOTREACHED*/ \ +} while (/*CONSTCOND*/0) + +#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; + 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) + ERR(EAI_BADHINTS); /* xxx */ + if (hints->ai_flags & ~AI_MASK) + ERR(EAI_BADFLAGS); + switch (hints->ai_family) { + case PF_UNSPEC: + case PF_INET: + case PF_INET6: + break; + default: + ERR(EAI_FAMILY); + } + memcpy(pai, hints, sizeof(*pai)); + + /* + * 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) { + ERR(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 */ + ERR(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) + ERR(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) + ERR(EAI_NONAME); + if (hostname == NULL) + ERR(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. */ + + /* we must not have got any errors. */ + if (error != 0) /* just for diagnosis */ + abort(); + + 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 && cur->ai_next) + cur = cur->ai_next; + } else + ERR(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 && cur->ai_next) + cur = cur->ai_next; + } else + ERR(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)) { + /* + * 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 && 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.2.4rc7/lib/bind/irs/getgrent.c b/contrib/bind-9.2.4rc7/lib/bind/irs/getgrent.c new file mode 100644 index 0000000000..1dd7ce046f --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/getgrent.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(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: getgrent.c,v 1.3.2.1 2004/03/09 09:17:29 marka 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 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/getgrent_r.c b/contrib/bind-9.2.4rc7/lib/bind/irs/getgrent_r.c new file mode 100644 index 0000000000..e7770146f9 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/getgrent_r.c @@ -0,0 +1,229 @@ +/* + * 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.5.2.1 2004/03/09 09:17:29 marka 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) */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/gethostent.c b/contrib/bind-9.2.4rc7/lib/bind/irs/gethostent.c new file mode 100644 index 0000000000..7173511005 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/gethostent.c @@ -0,0 +1,1069 @@ +/* + * 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.1.2.4 2004/03/17 01:54:20 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 + +#ifdef __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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/gethostent_r.c b/contrib/bind-9.2.4rc7/lib/bind/irs/gethostent_r.c new file mode 100644 index 0000000000..0caf02a94a --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/gethostent_r.c @@ -0,0 +1,262 @@ +/* + * 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.4.2.2 2004/04/22 03:21:02 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 + + HOST_R_ERRNO; + +#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 + + HOST_R_ERRNO; + +#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 + + HOST_R_ERRNO; + +#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 +{ + 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 +{ + 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) */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/getnameinfo.c b/contrib/bind-9.2.4rc7/lib/bind/irs/getnameinfo.c new file mode 100644 index 0000000000..5947c03898 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/getnameinfo.c @@ -0,0 +1,322 @@ +/* + * Issues to be discussed: + * - Thread safe-ness must be checked + */ + +/* + * 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 diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/getnetent.c b/contrib/bind-9.2.4rc7/lib/bind/irs/getnetent.c new file mode 100644 index 0000000000..6be115edae --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/getnetent.c @@ -0,0 +1,343 @@ +/* + * 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.4.2.2 2004/03/17 01:54:21 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 "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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/getnetent_r.c b/contrib/bind-9.2.4rc7/lib/bind/irs/getnetent_r.c new file mode 100644 index 0000000000..3f6e333f68 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/getnetent_r.c @@ -0,0 +1,227 @@ +/* + * 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.3.2.1 2004/03/09 09:17:30 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 +{ + 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 +{ + 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) */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/getnetgrent.c b/contrib/bind-9.2.4rc7/lib/bind/irs/getnetgrent.c new file mode 100644 index 0000000000..815d28fd44 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/getnetgrent.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: getnetgrent.c,v 1.1.2.2 2004/03/09 09:17:30 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(char **host, char **user, 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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/getnetgrent_r.c b/contrib/bind-9.2.4rc7/lib/bind/irs/getnetgrent_r.c new file mode 100644 index 0000000000..085867df72 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/getnetgrent_r.c @@ -0,0 +1,167 @@ +/* + * 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.5.2.3 2004/04/13 04:49:01 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 +#include + +#ifdef NGR_R_RETURN + +static NGR_R_RETURN +copy_protoent(char **, char **, 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(char **machinep, char **userp, char **domainp, NGR_R_ARGS) { + 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)); +} + +NGR_R_SET_RETURN +#ifdef NGR_R_ENT_ARGS +setnetgrent_r(const char *netgroup, NGR_R_ENT_ARGS) +#else +setnetgrent_r(const char *netgroup) +#endif +{ + char *tmp; + DE_CONST(netgroup, tmp); + setnetgrent(tmp); +#ifdef NGR_R_PRIVATE + *buf = NULL; +#endif +#ifdef NGR_R_SET_RESULT + return (NGR_R_SET_RESULT); +#endif +} + +NGR_R_END_RETURN +#ifdef NGR_R_ENT_ARGS +endnetgrent_r(NGR_R_ENT_ARGS) +#else +endnetgrent_r(void) +#endif +{ + endnetgrent(); +#ifdef NGR_R_PRIVATE + if (*buf != NULL) + free(*buf); + *buf = NULL; +#endif + NGR_R_END_RESULT(NGR_R_OK); +} + +/* Private */ + +static int +copy_protoent(char **machinep, char **userp, char **domainp, + const char *mp, const char *up, const char *dp, + NGR_R_COPY_ARGS) { + 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; + +#ifdef NGR_R_PRIVATE + free(*buf); + *buf = malloc(len); + if (*buf == NULL) + return(NGR_R_BAD); + cp = *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) */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/getprotoent.c b/contrib/bind-9.2.4rc7/lib/bind/irs/getprotoent.c new file mode 100644 index 0000000000..db9dc11be5 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/getprotoent.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: getprotoent.c,v 1.2.2.1 2004/03/09 09:17:30 marka 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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/getprotoent_r.c b/contrib/bind-9.2.4rc7/lib/bind/irs/getprotoent_r.c new file mode 100644 index 0000000000..e74e3cbad5 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/getprotoent_r.c @@ -0,0 +1,216 @@ +/* + * 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.3.2.1 2004/03/09 09:17:30 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 +{ + 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 +{ + 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) */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/getpwent.c b/contrib/bind-9.2.4rc7/lib/bind/irs/getpwent.c new file mode 100644 index 0000000000..1e13df69cc --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/getpwent.c @@ -0,0 +1,200 @@ +/* + * 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.1.2.1 2004/03/09 09:17:30 marka 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 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/getpwent_r.c b/contrib/bind-9.2.4rc7/lib/bind/irs/getpwent_r.c new file mode 100644 index 0000000000..a2adebf031 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/getpwent_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: getpwent_r.c,v 1.5.2.1 2004/03/09 09:17:31 marka 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; + + 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; + + 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) */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/getservent.c b/contrib/bind-9.2.4rc7/lib/bind/irs/getservent.c new file mode 100644 index 0000000000..300d9ca829 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/getservent.c @@ -0,0 +1,177 @@ +/* + * 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.2.2.1 2004/03/09 09:17:31 marka 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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/getservent_r.c b/contrib/bind-9.2.4rc7/lib/bind/irs/getservent_r.c new file mode 100644 index 0000000000..87078b0ec7 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/getservent_r.c @@ -0,0 +1,237 @@ +/* + * 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.3.2.1 2004/03/09 09:17:31 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 +{ + + 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 +{ + + 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 = ndptr->line; + eob = ndptr->line + sizeof(ndptr->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 = ndptr->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) */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/hesiod.c b/contrib/bind-9.2.4rc7/lib/bind/irs/hesiod.c new file mode 100644 index 0000000000..71144d765f --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/hesiod.c @@ -0,0 +1,507 @@ +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: hesiod.c,v 1.1.2.4 2004/05/17 07:46:43 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. + */ + +/* + * This file is primarily maintained by and . + */ + +/* + * 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. + */ + +/* 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); + } + + ctx->LHS = NULL; + ctx->RHS = NULL; + ctx->res = NULL; + + 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.2.4rc7/lib/bind/irs/hesiod_p.h b/contrib/bind-9.2.4rc7/lib/bind/irs/hesiod_p.h new file mode 100644 index 0000000000..ba72b96e3e --- /dev/null +++ b/contrib/bind-9.2.4rc7/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. + */ + +/* + * This file is primarily maintained by and . + */ + +/* + * $Id: hesiod_p.h,v 1.1.2.1 2004/03/09 09:17:31 marka Exp $ + */ + +/* + * hesiod_p.h -- private definitions for the hesiod library + */ + +#ifndef _HESIOD_P_H_INCLUDED +#define _HESIOD_P_H_INCLUDED + +#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.2.4rc7/lib/bind/irs/irp.c b/contrib/bind-9.2.4rc7/lib/bind/irs/irp.c new file mode 100644 index 0000000000..9c73310684 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/irp.c @@ -0,0 +1,592 @@ +/* + * 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.3.2.3 2004/03/17 01:54:21 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; + + 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 + * struture. 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); + todo = vsprintf(buffer, fmt, ap); + 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); +} + + + diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/irp_gr.c b/contrib/bind-9.2.4rc7/lib/bind/irs/irp_gr.c new file mode 100644 index 0000000000..fa17c41139 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/irp_gr.c @@ -0,0 +1,408 @@ +/* + * 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.2.2.1 2004/03/09 09:17:31 marka 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. */ + +/* + * Module for the getnetgrent(3) family to use when connected to a + * remote irp daemon. + * + * 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. */ + + + + + +/* + * struct irs_gr * irs_irp_gr(struct irs_acc *this) + * + * Notes: + * + * Initialize the group sub-module. + * + * Notes: + * + * Module data. + * + */ + +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. */ + + + +/* + * void gr_close(struct irs_gr *this) + * + * Notes: + * + * 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); +} + + + + +/* + * struct group * gr_next(struct irs_gr *this) + * + * Notes: + * + * 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); +} + + + + + +/* + * struct group * gr_byname(struct irs_gr *this, const char *name) + * + * Notes: + * + * 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); +} + + + + + +/* + * struct group * gr_bygid(struct irs_gr *this, gid_t gid) + * + * Notes: + * + * 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; +} + + + + +/* + * void gr_minimize(struct irs_gr *this) + * + * Notes: + * + * 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 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/irp_ho.c b/contrib/bind-9.2.4rc7/lib/bind/irs/irp_ho.c new file mode 100644 index 0000000000..37949b2a0a --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/irp_ho.c @@ -0,0 +1,429 @@ +/* + * 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.1.2.1 2004/03/09 09:17:31 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 +#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. */ + + + +/* + * void ho_close(struct irs_ho *this) + * + * Notes: + * + * 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); +} + + + + + +/* + * struct hostent * ho_next(struct irs_ho *this) + * + * Notes: + * + * 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/irp_ng.c b/contrib/bind-9.2.4rc7/lib/bind/irs/irp_ng.c new file mode 100644 index 0000000000..6906f1d221 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/irp_ng.c @@ -0,0 +1,272 @@ +/* + * 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.1.2.1 2004/03/09 09:17:31 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 */ + + + +/* + * struct irs_ng * irs_irp_ng(struct irs_acc *this) + * + * Notes: + * + * 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; +} + + + + +/* + * int ng_next(struct irs_ng *this, const char **host, const char **user, + * const char **domain) + * + * Notes: + * + * 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); +} + + + +/* + * int ng_test(struct irs_ng *this, const char *name, const char *host, + * const char *user, const char *domain) + * + * Notes: + * + * 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) { + memput(body, bodylen); + + code = irs_irp_read_response(pvt->girpdata, text, sizeof text); + if (code == IRPD_GETNETGR_MATCHES) { + rval = 1; + } + } + + 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 */ + diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/irp_nw.c b/contrib/bind-9.2.4rc7/lib/bind/irs/irp_nw.c new file mode 100644 index 0000000000..ed7bd1811e --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/irp_nw.c @@ -0,0 +1,375 @@ +/* + * 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.1.2.1 2004/03/09 09:17:31 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; +} + + + + + + +/* + * struct nwent * nw_next(struct irs_nw *this) + * + * Notes: + * + * 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; + } + + 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. */ + + + +/* + * static void free_passwd(struct passwd *pw); + * + * 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/irp_p.h b/contrib/bind-9.2.4rc7/lib/bind/irs/irp_p.h new file mode 100644 index 0000000000..872d5e9114 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/irp_p.h @@ -0,0 +1,59 @@ +/* + * 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.1.2.3 2004/03/09 09:17:31 marka 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 diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/irp_pr.c b/contrib/bind-9.2.4rc7/lib/bind/irs/irp_pr.c new file mode 100644 index 0000000000..84152ed073 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/irp_pr.c @@ -0,0 +1,353 @@ +/* + * 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.1.2.1 2004/03/09 09:17:31 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 +#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; +} + + + + +/* + * struct protoent * pr_next(struct irs_pr *this) + * + * Notes: + * + * 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); +} + + + + + + +/* + * static void free_proto(struct protoent *pw); + * + * 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/irp_pw.c b/contrib/bind-9.2.4rc7/lib/bind/irs/irp_pw.c new file mode 100644 index 0000000000..ef728e97d1 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/irp_pw.c @@ -0,0 +1,358 @@ +/* + * 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.2.2.1 2004/03/09 09:17:32 marka 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. */ + + + +/* + * static void free_passwd(struct passwd *pw); + * + * 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 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/irp_sv.c b/contrib/bind-9.2.4rc7/lib/bind/irs/irp_sv.c new file mode 100644 index 0000000000..316bec3446 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/irp_sv.c @@ -0,0 +1,369 @@ +/* + * 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.1.2.1 2004/03/09 09:17:32 marka 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); +} + + + + +/* + * struct servent * sv_next(struct irs_sv *this) + * + * Notes: + * + * 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); + } +} + + diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/irpmarshall.c b/contrib/bind-9.2.4rc7/lib/bind/irs/irpmarshall.c new file mode 100644 index 0000000000..8776b16e4f --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/irpmarshall.c @@ -0,0 +1,2344 @@ +/* + * 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.3.2.3 2004/03/17 01:15:47 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: + * + * See above + * + * return: + * + * 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: + * + * see above + * + * return: + * + * 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: + * + * see above. + * + * return: + * + * 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: + * + * see above + * + * return: + * + * 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: + * + * see above + * + * return: + * + * 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: + * + * see above + * + * return: + * + * 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: + * + * see above + * + * return: + * + * 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: + * + * See above + * + * return: + * + * 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: + * + * see above. + * + * return: + * + * 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: + * + * See above. + * + * return: + * + * 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 = NULL; + 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(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: + * + * See note for irp_marshall_ng_start + * + * return: + * + * 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: + * + * 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: + * + * 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); + if (domain != NULL) free(domain); + + return (-1); +} + +/* ------------------------- struct netgrp ------------------------- */ + + + + +/* +++++++++++++++++++++++++ struct nwent +++++++++++++++++++++++++ */ + + +/* + * int irp_marshall_nw(struct nwent *ne, char **buffer, size_t *len) + * + * notes: + * + * See at top. + * + * return: + * + * 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: + * + * See note up top. + * + * return: + * + * 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: + * + * See at top. + * + * return: + * + * 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: + * + * See note up top. + * + * return: + * + * 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: + * + * 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: + * + * 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: + * + * 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: + * + * 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: + * + * 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: + * + * 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: + * + * 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: + * + * like strdup, except do len bytes instead of the whole string. Always + * null-terminates. + * + * return: + * + * 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: + * + * do a strcmp, except uneven lengths of whitespace compare the same + * + * return: + * + */ + +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: + * + * 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 diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/irs_data.c b/contrib/bind-9.2.4rc7/lib/bind/irs/irs_data.c new file mode 100644 index 0000000000..3f6db55d2c --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/irs_data.c @@ -0,0 +1,230 @@ +/* + * 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.3.2.4 2004/03/17 00:40:13 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 + static pthread_mutex_t keylock = PTHREAD_MUTEX_INITIALIZER; + struct net_data *net_data; + + if (!once) { + pthread_mutex_lock(&keylock); + if (!once++) + pthread_key_create(&key, net_data_destroy); + pthread_mutex_unlock(&keylock); + } + 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 + pthread_setspecific(key, net_data); +#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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/irs_data.h b/contrib/bind-9.2.4rc7/lib/bind/irs/irs_data.h new file mode 100644 index 0000000000..6318bd4b27 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/irs_data.h @@ -0,0 +1,62 @@ +/* + * 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.1.2.1 2004/03/09 09:17:32 marka 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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/irs_p.h b/contrib/bind-9.2.4rc7/lib/bind/irs/irs_p.h new file mode 100644 index 0000000000..d997b6064e --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/irs_p.h @@ -0,0 +1,49 @@ +/* + * 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.1.2.1 2004/03/09 09:17:32 marka 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 diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/lcl.c b/contrib/bind-9.2.4rc7/lib/bind/irs/lcl.c new file mode 100644 index 0000000000..e14ed52247 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/lcl.c @@ -0,0 +1,140 @@ +/* + * 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.1.2.2 2004/03/17 00:40:13 marka 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/lcl_gr.c b/contrib/bind-9.2.4rc7/lib/bind/irs/lcl_gr.c new file mode 100644 index 0000000000..5564c08b1c --- /dev/null +++ b/contrib/bind-9.2.4rc7/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.1.2.1 2004/03/09 09:17:32 marka 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 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/lcl_ho.c b/contrib/bind-9.2.4rc7/lib/bind/irs/lcl_ho.c new file mode 100644 index 0000000000..865566179a --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/lcl_ho.c @@ -0,0 +1,576 @@ +/* + * 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.1.2.2 2004/03/17 00:40:13 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 && 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/lcl_ng.c b/contrib/bind-9.2.4rc7/lib/bind/irs/lcl_ng.c new file mode 100644 index 0000000000..756a790f8a --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/lcl_ng.c @@ -0,0 +1,444 @@ +/* + * 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.1.2.1 2004/03/09 09:17:32 marka 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: + * - linelist is just used by setnetgrent() to parse the net group file via. + * parse_netgrp() + * - 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/lcl_nw.c b/contrib/bind-9.2.4rc7/lib/bind/irs/lcl_nw.c new file mode 100644 index 0000000000..b31f785a84 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/lcl_nw.c @@ -0,0 +1,371 @@ +/* + * 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.1.2.2 2004/03/17 00:40:13 marka 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/lcl_p.h b/contrib/bind-9.2.4rc7/lib/bind/irs/lcl_p.h new file mode 100644 index 0000000000..0f6b011c77 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/lcl_p.h @@ -0,0 +1,50 @@ +/* + * 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.1.2.1 2004/03/09 09:17:33 marka Exp $ + */ + +/* + * 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.2.4rc7/lib/bind/irs/lcl_pr.c b/contrib/bind-9.2.4rc7/lib/bind/irs/lcl_pr.c new file mode 100644 index 0000000000..8acd07000e --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/lcl_pr.c @@ -0,0 +1,284 @@ +/* + * 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.1.2.1 2004/03/09 09:17:33 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]; + 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); + 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); + 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; + 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; + } +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/lcl_pw.c b/contrib/bind-9.2.4rc7/lib/bind/irs/lcl_pw.c new file mode 100644 index 0000000000..6b15fbfc36 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/lcl_pw.c @@ -0,0 +1,308 @@ +/* + * 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.1.2.1 2004/03/09 09:17:33 marka 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" + +/* + * 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.2.4rc7/lib/bind/irs/lcl_sv.c b/contrib/bind-9.2.4rc7/lib/bind/irs/lcl_sv.c new file mode 100644 index 0000000000..9015b2fa02 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/lcl_sv.c @@ -0,0 +1,431 @@ +/* + * 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.2.2.1 2004/03/09 09:17:33 marka 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 diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/nis.c b/contrib/bind-9.2.4rc7/lib/bind/irs/nis.c new file mode 100644 index 0000000000..828128e1ce --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/nis.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: nis.c,v 1.1.2.1 2004/03/09 09:17:33 marka 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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/nis_gr.c b/contrib/bind-9.2.4rc7/lib/bind/irs/nis_gr.c new file mode 100644 index 0000000000..bee0b2ed8e --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/nis_gr.c @@ -0,0 +1,353 @@ +/* + * 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.1.2.2 2004/03/09 09:17:33 marka 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 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/nis_ho.c b/contrib/bind-9.2.4rc7/lib/bind/irs/nis_ho.c new file mode 100644 index 0000000000..5f86a004f2 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/nis_ho.c @@ -0,0 +1,533 @@ +/* + * 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.2.2.2 2004/03/09 09:17:33 marka 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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/nis_ng.c b/contrib/bind-9.2.4rc7/lib/bind/irs/nis_ng.c new file mode 100644 index 0000000000..ad9bdf3182 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/nis_ng.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_ng.c,v 1.2.2.1 2004/03/09 09:17:33 marka 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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/nis_nw.c b/contrib/bind-9.2.4rc7/lib/bind/irs/nis_nw.c new file mode 100644 index 0000000000..1504f081bb --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/nis_nw.c @@ -0,0 +1,383 @@ +/* + * 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.2.2.1 2004/03/09 09:17:33 marka 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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/nis_p.h b/contrib/bind-9.2.4rc7/lib/bind/irs/nis_p.h new file mode 100644 index 0000000000..bef2e03066 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/nis_p.h @@ -0,0 +1,46 @@ +/* + * 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.1.2.1 2004/03/09 09:17:33 marka Exp $ + */ + +/* + * 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.2.4rc7/lib/bind/irs/nis_pr.c b/contrib/bind-9.2.4rc7/lib/bind/irs/nis_pr.c new file mode 100644 index 0000000000..6fe55a5e83 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/nis_pr.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: nis_pr.c,v 1.2.2.1 2004/03/09 09:17:33 marka 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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/nis_pw.c b/contrib/bind-9.2.4rc7/lib/bind/irs/nis_pw.c new file mode 100644 index 0000000000..d44033c879 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/nis_pw.c @@ -0,0 +1,287 @@ +/* + * 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.2.2.1 2004/03/09 09:17:33 marka 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 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/nis_sv.c b/contrib/bind-9.2.4rc7/lib/bind/irs/nis_sv.c new file mode 100644 index 0000000000..d48224692e --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/nis_sv.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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: nis_sv.c,v 1.2.2.1 2004/03/09 09:17:34 marka 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*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/nul_ng.c b/contrib/bind-9.2.4rc7/lib/bind/irs/nul_ng.c new file mode 100644 index 0000000000..e93be8b11f --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/nul_ng.c @@ -0,0 +1,126 @@ +/* + * 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.1.2.1 2004/03/09 09:17:34 marka Exp $"; +#endif + +/* + * 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.2.4rc7/lib/bind/irs/pathnames.h b/contrib/bind-9.2.4rc7/lib/bind/irs/pathnames.h new file mode 100644 index 0000000000..cea4a0beed --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/pathnames.h @@ -0,0 +1,50 @@ +/* + * 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.1.2.1 2004/03/09 09:17:34 marka 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 diff --git a/contrib/bind-9.2.4rc7/lib/bind/irs/util.c b/contrib/bind-9.2.4rc7/lib/bind/irs/util.c new file mode 100644 index 0000000000..6ee2c6216b --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/irs/util.c @@ -0,0 +1,107 @@ +/* + * 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.1.2.1 2004/03/09 09:17:34 marka 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/assertions.c b/contrib/bind-9.2.4rc7/lib/bind/isc/assertions.c new file mode 100644 index 0000000000..b8a38e3e90 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/assertions.c @@ -0,0 +1,91 @@ +/* + * 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.1.2.1 2004/03/09 09:17:34 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. + */ + +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 */ +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/assertions.mdoc b/contrib/bind-9.2.4rc7/lib/bind/isc/assertions.mdoc new file mode 100644 index 0000000000..7ca055df94 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/assertions.mdoc @@ -0,0 +1,138 @@ +.\" $Id: assertions.mdoc,v 1.1.2.2 2004/03/09 09:17:34 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.2.4rc7/lib/bind/isc/base64.c b/contrib/bind-9.2.4rc7/lib/bind/isc/base64.c new file mode 100644 index 0000000000..a21c73dd31 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/base64.c @@ -0,0 +1,320 @@ +/* + * 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.1.2.2 2004/03/17 00:40:13 marka 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 RFC 1521 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/bitncmp.c b/contrib/bind-9.2.4rc7/lib/bind/isc/bitncmp.c new file mode 100644 index 0000000000..1223f8b151 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/bitncmp.c @@ -0,0 +1,66 @@ +/* + * 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.1.2.1 2004/03/09 09:17:34 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) + 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/bitncmp.mdoc b/contrib/bind-9.2.4rc7/lib/bind/isc/bitncmp.mdoc new file mode 100644 index 0000000000..9938fb8ddc --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/bitncmp.mdoc @@ -0,0 +1,82 @@ +.\" $Id: bitncmp.mdoc,v 1.1.2.2 2004/03/09 09:17:34 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.2.4rc7/lib/bind/isc/ctl_clnt.c b/contrib/bind-9.2.4rc7/lib/bind/isc/ctl_clnt.c new file mode 100644 index 0000000000..1d3980c236 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/ctl_clnt.c @@ -0,0 +1,602 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: ctl_clnt.c,v 1.4.2.4 2004/03/17 01:15:48 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 +#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); + +/* 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/ctl_p.c b/contrib/bind-9.2.4rc7/lib/bind/isc/ctl_p.c new file mode 100644 index 0000000000..deb461f7d0 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/ctl_p.c @@ -0,0 +1,186 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: ctl_p.c,v 1.1.2.2 2004/03/17 00:40:14 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 +#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; + } +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/ctl_p.h b/contrib/bind-9.2.4rc7/lib/bind/isc/ctl_p.h new file mode 100644 index 0000000000..42aade7d66 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/ctl_p.h @@ -0,0 +1,26 @@ +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 *); diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/ctl_srvr.c b/contrib/bind-9.2.4rc7/lib/bind/isc/ctl_srvr.c new file mode 100644 index 0000000000..91b9e9aeb6 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/ctl_srvr.c @@ -0,0 +1,780 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: ctl_srvr.c,v 1.3.2.4 2004/03/17 01:15:48 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 + +#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 = sess->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); + 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; + } +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/ev_connects.c b/contrib/bind-9.2.4rc7/lib/bind/isc/ev_connects.c new file mode 100644 index 0000000000..9529c4158c --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/ev_connects.c @@ -0,0 +1,367 @@ +/* + * 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.4.2.1 2004/03/09 09:17:35 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; + OK(mode = fcntl(fd, F_GETFL, NULL)); /* 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; + OK(ioctl(fd, FIONBIO, (char *)&on)); +#else + OK(fcntl(fd, F_SETFL, mode | PORT_NONBLOCK)); +#endif + new->flags |= EV_CONN_BLOCK; + } + OK(listen(fd, maxconn)); + 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 on = 1; + OK(ioctl(this->fd, FIONBIO, (char *)&on)); +#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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/ev_files.c b/contrib/bind-9.2.4rc7/lib/bind/isc/ev_files.c new file mode 100644 index 0000000000..2582cfc3f4 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/ev_files.c @@ -0,0 +1,283 @@ +/* + * 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.3.2.2 2004/03/09 09:17:35 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); + if (fd > ctx->highestFD) + EV_ERR(EINVAL); + 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. + */ + 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; + + evPrintf(ctx, 5, + "evSelectFD(fd %d, mask 0x%x): new masks: 0x%lx 0x%lx 0x%lx\n", + fd, eventmask, + (u_long)ctx->rdNext.fds_bits[0], + (u_long)ctx->wrNext.fds_bits[0], + (u_long)ctx->exNext.fds_bits[0]); + + 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 = 1; + (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; + + evPrintf(ctx, 5, + "evDeselectFD(fd %d, mask 0x%x): new masks: 0x%lx 0x%lx 0x%lx\n", + del->fd, eventmask, + (u_long)ctx->rdNext.fds_bits[0], + (u_long)ctx->wrNext.fds_bits[0], + (u_long)ctx->exNext.fds_bits[0]); + + /* 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/ev_streams.c b/contrib/bind-9.2.4rc7/lib/bind/isc/ev_streams.c new file mode 100644 index 0000000000..9fb05f4c47 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/ev_streams.c @@ -0,0 +1,306 @@ +/* + * 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.2.2.2 2004/03/17 00:40:14 marka 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/ev_timers.c b/contrib/bind-9.2.4rc7/lib/bind/isc/ev_timers.c new file mode 100644 index 0000000000..076eb3b4a8 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/ev_timers.c @@ -0,0 +1,497 @@ +/* + * 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.2.2.6 2004/03/17 02:33:17 marka 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); + } +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/ev_waits.c b/contrib/bind-9.2.4rc7/lib/bind/isc/ev_waits.c new file mode 100644 index 0000000000..f5250889d6 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/ev_waits.c @@ -0,0 +1,245 @@ +/* + * 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.1.2.2 2004/03/09 09:17:35 marka 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/eventlib.c b/contrib/bind-9.2.4rc7/lib/bind/isc/eventlib.c new file mode 100644 index 0000000000..9d15f41d79 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/eventlib.c @@ -0,0 +1,728 @@ +/* + * 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.2.2.3 2004/03/17 01:54:22 marka Exp $"; +#endif + +#include "port_before.h" +#include "fd_setsize.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include "eventlib_p.h" + +#include "port_after.h" + +/* Forward. */ + +#ifdef NEED_PSELECT +static int pselect(int, void *, void *, void *, + struct timespec *, + const sigset_t *); +#endif + +/* 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; + 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. */ + ctx->highestFD = FD_SETSIZE - 1; +#ifdef EVENTLIB_TIME_CHECKS + ctx->lastFdCount = 0; +#endif + memset(ctx->fdTable, 0, sizeof ctx->fdTable); + + /* 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 { + /* XXX need to copy only the bits we are using. */ + ctx->rdLast = ctx->rdNext; + ctx->wrLast = ctx->wrNext; + ctx->exLast = ctx->exNext; + + if (m == Timer) { + INSIST(tp == &t); + t = evSubTime(nextTime, ctx->lastEventTime); + } + + evPrintf(ctx, 4, + "pselect(%d, 0x%lx, 0x%lx, 0x%lx, %ld.%09ld)\n", + ctx->fdMax+1, + (u_long)ctx->rdLast.fds_bits[0], + (u_long)ctx->wrLast.fds_bits[0], + (u_long)ctx->exLast.fds_bits[0], + tp ? (long)tp->tv_sec : -1L, + tp ? tp->tv_nsec : -1); + + /* XXX should predict system's earliness and adjust. */ + x = pselect(ctx->fdMax+1, + &ctx->rdLast, &ctx->wrLast, &ctx->exLast, + tp, NULL); + pselect_errno = errno; + + evPrintf(ctx, 4, "select() returns %d (err: %s)\n", + x, (x == -1) ? strerror(errno) : "none"); + + /* 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); +} + +#ifdef NEED_PSELECT +/* 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; + + if (tsp) { + tvp = &tv; + tv = evTimeVal(*tsp); + } else + tvp = NULL; + if (sigmask) + sigprocmask(SIG_SETMASK, sigmask, &sigs); + n = select(nfds, rfds, wfds, efds, tvp); + if (sigmask) + sigprocmask(SIG_SETMASK, &sigs, NULL); + if (tsp) + *tsp = evTimeSpec(tv); + return (n); +} +#endif diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/eventlib.mdoc b/contrib/bind-9.2.4rc7/lib/bind/isc/eventlib.mdoc new file mode 100644 index 0000000000..d274692d2b --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/eventlib.mdoc @@ -0,0 +1,918 @@ +.\" $Id: eventlib.mdoc,v 1.1.2.2 2004/03/09 09:17:35 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.2.4rc7/lib/bind/isc/eventlib_p.h b/contrib/bind-9.2.4rc7/lib/bind/isc/eventlib_p.h new file mode 100644 index 0000000000..1bd11bc111 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/eventlib_p.h @@ -0,0 +1,219 @@ +/* + * 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_p.h - private interfaces for eventlib + * vix 09sep95 [initial] + * + * $Id: eventlib_p.h,v 1.3.2.2 2004/03/09 09:17:35 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 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 + +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; + +typedef struct { + /* Global. */ + const evEvent_p *cur; + /* Debugging. */ + int debug; + FILE *output; + /* Connections. */ + evConn *conns; + LIST(evAccept) accepts; + /* Files. */ + evFile *files, *fdNext; + fd_set rdLast, rdNext; + fd_set wrLast, wrNext; + fd_set exLast, exNext; + fd_set nonblockBefore; + int fdMax, fdCount, highestFD; + evFile *fdTable[FD_SETSIZE]; +#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); + +/* 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 */ +int __evOptMonoTime; + +#endif /*_EVENTLIB_P_H*/ diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/heap.c b/contrib/bind-9.2.4rc7/lib/bind/isc/heap.c new file mode 100644 index 0000000000..24aded77f6 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/heap.c @@ -0,0 +1,230 @@ +/* + * 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.1.2.1 2004/03/09 09:17:35 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; + + ctx = (heap_context)malloc(sizeof (struct heap_context)); + if (ctx == NULL || higher_priority == 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/heap.mdoc b/contrib/bind-9.2.4rc7/lib/bind/isc/heap.mdoc new file mode 100644 index 0000000000..bccdc9a9e8 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/heap.mdoc @@ -0,0 +1,378 @@ +.\" $Id: heap.mdoc,v 1.1.2.2 2004/03/09 09:17:35 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.2.4rc7/lib/bind/isc/hex.c b/contrib/bind-9.2.4rc7/lib/bind/isc/hex.c new file mode 100644 index 0000000000..c177ca0fa3 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/hex.c @@ -0,0 +1,116 @@ +/* + * 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 == ';') { + while ((c = fgetc(fp)) != EOF && c != '\n') + /* empty */ + 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'; +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/logging.c b/contrib/bind-9.2.4rc7/lib/bind/isc/logging.c new file mode 100644 index 0000000000..1ed56d8f36 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/logging.c @@ -0,0 +1,720 @@ +/* + * 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.3.2.3 2004/03/17 01:54:23 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" + +#ifdef VSPRINTF_CHAR +# define VSPRINTF(x) strlen(vsprintf/**/x) +#else +# define VSPRINTF(x) ((size_t)vsprintf x) +#endif + +#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) { + if (VSPRINTF((lc->buffer, format, args)) > + (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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/logging.mdoc b/contrib/bind-9.2.4rc7/lib/bind/isc/logging.mdoc new file mode 100644 index 0000000000..c52a81b95e --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/logging.mdoc @@ -0,0 +1,1056 @@ +.\" $Id: logging.mdoc,v 1.1.2.2 2004/03/09 09:17:36 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.2.4rc7/lib/bind/isc/logging_p.h b/contrib/bind-9.2.4rc7/lib/bind/isc/logging_p.h new file mode 100644 index 0000000000..99f6976f6c --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/logging_p.h @@ -0,0 +1,60 @@ +/* + * 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 */ diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/memcluster.c b/contrib/bind-9.2.4rc7/lib/bind/isc/memcluster.c new file mode 100644 index 0000000000..a7b91096c9 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/memcluster.c @@ -0,0 +1,545 @@ +/* + * 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. + */ + + +/* 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.3.2.3 2004/03/17 00:40:15 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; +}; + +/* Private data. */ + +static size_t max_size; +static size_t mem_target; +static size_t mem_target_half; +static size_t mem_target_fudge; +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; + mem_target_half = mem_target / 2; + mem_target_fudge = mem_target + mem_target / 4; + 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; + +#if !defined(MEMCLUSTER_RECORD) + UNUSED(file); + UNUSED(line); +#endif + if (freelists == NULL) + if (meminit(0, 0) == -1) + return (NULL); + if (size == 0U) { + 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) { + 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 + e->fencepost = FRONT_FENCEPOST; + p = (char *)e + sizeof *e + size; + memcpy(p, &fp, sizeof fp); + return ((char *)e + sizeof *e); +#else + 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) { + 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) { + 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--; +#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 + +#if !defined (MEMCLUSTER_RECORD) + UNUSED(file); + UNUSED(line); +#endif + + REQUIRE(freelists != NULL); + + if (size == 0U) { + 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(((int)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--; + 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++; +} + +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 + + if (freelists == NULL) + 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%5d: %11lu gets, %11lu rem", + (i == max_size) ? ">=" : " ", + 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:%d\n", + e->file != NULL ? e->file : + "", e->line, + (char *)e + sizeof *e, e->size); + e = e->next; + } + } +#endif +} + +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 diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/memcluster.mdoc b/contrib/bind-9.2.4rc7/lib/bind/isc/memcluster.mdoc new file mode 100644 index 0000000000..ce75bae1a1 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/memcluster.mdoc @@ -0,0 +1,376 @@ +.\" $Id: memcluster.mdoc,v 1.1.2.2 2004/03/09 09:17:36 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.2.4rc7/lib/bind/isc/movefile.c b/contrib/bind-9.2.4rc7/lib/bind/isc/movefile.c new file mode 100644 index 0000000000..8582aa72bd --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/movefile.c @@ -0,0 +1,35 @@ +/* + * 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 diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/tree.c b/contrib/bind-9.2.4rc7/lib/bind/isc/tree.c new file mode 100644 index 0000000000..b308b1cdab --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/tree.c @@ -0,0 +1,532 @@ +#ifndef LINT +static const char rcsid[] = "$Id: tree.c,v 1.2.2.1 2004/03/09 09:17:36 marka 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 +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/isc/tree.mdoc b/contrib/bind-9.2.4rc7/lib/bind/isc/tree.mdoc new file mode 100644 index 0000000000..4f3abb7b8d --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/isc/tree.mdoc @@ -0,0 +1,154 @@ +.\" $Id: tree.mdoc,v 1.1.2.2 2004/03/09 09:17:36 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.2.4rc7/lib/bind/ltmain.sh b/contrib/bind-9.2.4rc7/lib/bind/ltmain.sh new file mode 100644 index 0000000000..96c5835935 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/ltmain.sh @@ -0,0 +1,4950 @@ +# ltmain.sh - Provide generalized library-building support services. +# NOTE: Changing this file will not affect anything until you rerun configure. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Check that we have a working $echo. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell, and then maybe $echo will work. + exec $SHELL "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <&2 + echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 +fi + +# Global variables. +mode=$default_mode +nonopt= +prev= +prevopt= +run= +show="$echo" +show_help= +execute_dlfiles= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" + +# Parse our command line options once, thoroughly. +while test $# -gt 0 +do + arg="$1" + shift + + case $arg in + -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + execute_dlfiles) + execute_dlfiles="$execute_dlfiles $arg" + ;; + *) + eval "$prev=\$arg" + ;; + esac + + prev= + prevopt= + continue + fi + + # Have we seen a non-optional argument yet? + case $arg in + --help) + show_help=yes + ;; + + --version) + echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" + exit 0 + ;; + + --config) + sed -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $0 + exit 0 + ;; + + --debug) + echo "$progname: enabling shell trace mode" + set -x + ;; + + --dry-run | -n) + run=: + ;; + + --features) + echo "host: $host" + if test "$build_libtool_libs" = yes; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + exit 0 + ;; + + --finish) mode="finish" ;; + + --mode) prevopt="--mode" prev=mode ;; + --mode=*) mode="$optarg" ;; + + --quiet | --silent) + show=: + ;; + + -dlopen) + prevopt="-dlopen" + prev=execute_dlfiles + ;; + + -*) + $echo "$modename: unrecognized option \`$arg'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + + *) + nonopt="$arg" + break + ;; + esac +done + +if test -n "$prevopt"; then + $echo "$modename: option \`$prevopt' requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 +fi + +if test -z "$show_help"; then + + # Infer the operation mode. + if test -z "$mode"; then + case $nonopt in + *cc | *++ | gcc* | *-gcc*) + mode=link + for arg + do + case $arg in + -c) + mode=compile + break + ;; + esac + done + ;; + *db | *dbx | *strace | *truss) + mode=execute + ;; + *install*|cp|mv) + mode=install + ;; + *rm) + mode=uninstall + ;; + *) + # If we have no mode, but dlfiles were specified, then do execute mode. + test -n "$execute_dlfiles" && mode=execute + + # Just use the default operation mode. + if test -z "$mode"; then + if test -n "$nonopt"; then + $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 + else + $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 + fi + fi + ;; + esac + fi + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + $echo "$modename: unrecognized option \`-dlopen'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$modename --help --mode=$mode' for more information." + + # These modes are in order of execution frequency so that they run quickly. + case $mode in + # libtool compile mode + compile) + modename="$modename: compile" + # Get the compilation command and the source file. + base_compile= + prev= + lastarg= + srcfile="$nonopt" + suppress_output= + + user_target=no + for arg + do + case $prev in + "") ;; + xcompiler) + # Aesthetically quote the previous argument. + prev= + lastarg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + + case $arg in + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + + # Add the previous argument to base_compile. + if test -z "$base_compile"; then + base_compile="$lastarg" + else + base_compile="$base_compile $lastarg" + fi + continue + ;; + esac + + # Accept any command-line options. + case $arg in + -o) + if test "$user_target" != "no"; then + $echo "$modename: you cannot specify \`-o' more than once" 1>&2 + exit 1 + fi + user_target=next + ;; + + -static) + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"` + lastarg= + IFS="${IFS= }"; save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + lastarg="$lastarg $arg" + done + IFS="$save_ifs" + lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"` + + # Add the arguments to base_compile. + if test -z "$base_compile"; then + base_compile="$lastarg" + else + base_compile="$base_compile $lastarg" + fi + continue + ;; + esac + + case $user_target in + next) + # The next one is the -o target name + user_target=yes + continue + ;; + yes) + # We got the output file + user_target=set + libobj="$arg" + continue + ;; + esac + + # Accept the current argument as the source file. + lastarg="$srcfile" + srcfile="$arg" + + # Aesthetically quote the previous argument. + + # Backslashify any backslashes, double quotes, and dollar signs. + # These are the only characters that are still specially + # interpreted inside of double-quoted scrings. + lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + case $lastarg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + lastarg="\"$lastarg\"" + ;; + esac + + # Add the previous argument to base_compile. + if test -z "$base_compile"; then + base_compile="$lastarg" + else + base_compile="$base_compile $lastarg" + fi + done + + case $user_target in + set) + ;; + no) + # Get the name of the library object. + libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` + ;; + *) + $echo "$modename: you must specify a target with \`-o'" 1>&2 + exit 1 + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + xform='[cCFSfmso]' + case $libobj in + *.ada) xform=ada ;; + *.adb) xform=adb ;; + *.ads) xform=ads ;; + *.asm) xform=asm ;; + *.c++) xform=c++ ;; + *.cc) xform=cc ;; + *.cpp) xform=cpp ;; + *.cxx) xform=cxx ;; + *.f90) xform=f90 ;; + *.for) xform=for ;; + esac + + libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` + + case $libobj in + *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; + *) + $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 + exit 1 + ;; + esac + + if test -z "$base_compile"; then + $echo "$modename: you must specify a compilation command" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $libobj" + else + removelist="$libobj" + fi + + $run $rm $removelist + trap "$run $rm $removelist; exit 1" 1 2 15 + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2*) + pic_mode=default + ;; + esac + if test $pic_mode = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + removelist="$removelist $output_obj $lockfile" + trap "$run $rm $removelist; exit 1" 1 2 15 + else + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $run ln "$0" "$lockfile" 2>/dev/null; do + $show "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + echo "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit 1 + fi + echo $srcfile > "$lockfile" + fi + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + # All platforms use -DPIC, to notify preprocessed assembler code. + command="$base_compile $srcfile $pic_flag -DPIC" + else + # Don't build PIC code + command="$base_compile $srcfile" + fi + if test "$build_old_libs" = yes; then + lo_libobj="$libobj" + dir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$libobj"; then + dir="$objdir" + else + dir="$dir/$objdir" + fi + libobj="$dir/"`$echo "X$libobj" | $Xsed -e 's%^.*/%%'` + + if test -d "$dir"; then + $show "$rm $libobj" + $run $rm $libobj + else + $show "$mkdir $dir" + $run $mkdir $dir + status=$? + if test $status -ne 0 && test ! -d $dir; then + exit $status + fi + fi + fi + if test "$compiler_o_lo" = yes; then + output_obj="$libobj" + command="$command -o $output_obj" + elif test "$compiler_c_o" = yes; then + output_obj="$obj" + command="$command -o $output_obj" + fi + + $run $rm "$output_obj" + $show "$command" + if $run eval "$command"; then : + else + test -n "$output_obj" && $run $rm $removelist + exit 1 + fi + + if test "$need_locks" = warn && + test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then + echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit 1 + fi + + # Just move the object if needed, then go on to compile the next one + if test x"$output_obj" != x"$libobj"; then + $show "$mv $output_obj $libobj" + if $run $mv $output_obj $libobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # If we have no pic_flag, then copy the object into place and finish. + if (test -z "$pic_flag" || test "$pic_mode" != default) && + test "$build_old_libs" = yes; then + # Rename the .lo from within objdir to obj + if test -f $obj; then + $show $rm $obj + $run $rm $obj + fi + + $show "$mv $libobj $obj" + if $run $mv $libobj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$obj" | $Xsed -e "s%.*/%%"` + libobj=`$echo "X$baseobj" | $Xsed -e "$o2lo"` + # Now arrange that obj and lo_libobj become the same file + $show "(cd $xdir && $LN_S $baseobj $libobj)" + if $run eval '(cd $xdir && $LN_S $baseobj $libobj)'; then + exit 0 + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Allow error messages only from the first compilation. + suppress_output=' >/dev/null 2>&1' + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $srcfile" + else + # All platforms use -DPIC, to notify preprocessed assembler code. + command="$base_compile $srcfile $pic_flag -DPIC" + fi + if test "$compiler_c_o" = yes; then + command="$command -o $obj" + output_obj="$obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + command="$command$suppress_output" + $run $rm "$output_obj" + $show "$command" + if $run eval "$command"; then : + else + $run $rm $removelist + exit 1 + fi + + if test "$need_locks" = warn && + test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then + echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit 1 + fi + + # Just move the object if needed + if test x"$output_obj" != x"$obj"; then + $show "$mv $output_obj $obj" + if $run $mv $output_obj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Create an invalid libtool object if no PIC, so that we do not + # accidentally link it into a program. + if test "$build_libtool_libs" != yes; then + $show "echo timestamp > $libobj" + $run eval "echo timestamp > \$libobj" || exit $? + else + # Move the .lo from within objdir + $show "$mv $libobj $lo_libobj" + if $run $mv $libobj $lo_libobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + fi + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + $run $rm "$lockfile" + fi + + exit 0 + ;; + + # libtool link mode + link | relink) + modename="$modename: link" + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invokation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *-*-aix*) + allow_undefined=no + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args="$nonopt" + compile_command="$nonopt" + finalize_command="$nonopt" + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + + avoid_version=no + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -all-static | -static) + if test "X$arg" = "X-all-static"; then + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2 + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + else + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + fi + build_libtool_libs=no + build_old_libs=yes + prefer_static_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test $# -gt 0; do + arg="$1" + shift + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test + ;; + *) qarg=$arg ;; + esac + libtool_args="$libtool_args $qarg" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + compile_command="$compile_command @OUTPUT@" + finalize_command="$finalize_command @OUTPUT@" + ;; + esac + + case $prev in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + compile_command="$compile_command @SYMFILE@" + finalize_command="$finalize_command @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + if test ! -f "$arg"; then + $echo "$modename: symbol file \`$arg' does not exist" + exit 1 + fi + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit 1 + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + compile_command="$compile_command $wl$qarg" + finalize_command="$finalize_command $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n $prev + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 + allow_undefined=yes + continue + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: more than one -exported-symbols argument is not allowed" + exit 1 + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix*) + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + ;; + esac + continue + ;; + + -L*) + dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2 + exit 1 + fi + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + case :$dllsearchpath: in + *":$dir:"*) ;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-pw32* | *-*-beos*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-mingw* | *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + # The PATH hackery in wrapper scripts is required on Windows + # in order for the loader to find any dlls it needs. + $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2 + $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2 + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -o) prev=output ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit 1 + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -static) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'` + arg= + IFS="${IFS= }"; save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Wl,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'` + arg= + IFS="${IFS= }"; save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $wl$flag" + linker_flags="$linker_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + # Some other compiler flag. + -* | +*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + + *.lo | *.$objext) + # A library or standard object. + if test "$prev" = dlfiles; then + # This file was specified with -dlopen. + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $arg" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles "`$echo "X$arg" | $Xsed -e "$lo2o"` + prev= + else + case $arg in + *.lo) libobjs="$libobjs $arg" ;; + *) objs="$objs $arg" ;; + esac + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + done # argument parsing loop + + if test -n "$prev"; then + $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + + # calculate the name of the file, without its directory + outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` + if test "X$output_objdir" = "X$output"; then + output_objdir="$objdir" + else + output_objdir="$output_objdir/$objdir" + fi + # Create the object directory. + if test ! -d $output_objdir; then + $show "$mkdir $output_objdir" + $run $mkdir $output_objdir + status=$? + if test $status -ne 0 && test ! -d $output_objdir; then + exit $status + fi + fi + + # Determine the type of output + case $output in + "") + $echo "$modename: you must specify an output file" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + libs="$libs $deplib" + done + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + case $linkmode in + lib) + passes="conv link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2 + exit 1 + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + for pass in $passes; do + if test $linkmode = prog; then + # Determine which files to process + case $pass in + dlopen) + libs="$dlfiles" + save_deplibs="$deplibs" # Collect dlpreopened libraries + deplibs= + ;; + dlpreopen) libs="$dlprefiles" ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; + esac + fi + for deplib in $libs; do + lib= + found=no + case $deplib in + -l*) + if test $linkmode = oldlib && test $linkmode = obj; then + $echo "$modename: warning: \`-l' is ignored for archives/objects: $deplib" 1>&2 + continue + fi + if test $pass = conv; then + deplibs="$deplib $deplibs" + continue + fi + name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` + for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do + # Search the libtool library + lib="$searchdir/lib${name}.la" + if test -f "$lib"; then + found=yes + break + fi + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test $linkmode = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + ;; # -l + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test $pass = conv && continue + newdependency_libs="$deplib $newdependency_libs" + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + prog) + if test $pass = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test $pass = scan; then + deplibs="$deplib $deplibs" + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + ;; + *) + $echo "$modename: warning: \`-L' is ignored for archives/objects: $deplib" 1>&2 + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test $pass = link; then + dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'` + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test $pass = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + if test "$deplibs_check_method" != pass_all; then + echo + echo "*** Warning: This library needs some functionality provided by $deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + else + echo + echo "*** Warning: Linking the shared library $output against the" + echo "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + continue + ;; + prog) + if test $pass != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test $pass = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + if test $found = yes || test -f "$lib"; then : + else + $echo "$modename: cannot find the library \`$lib'" 1>&2 + exit 1 + fi + + # Check to see that this really is a libtool archive. + if (sed -e '2q' $lib | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit 1 + fi + + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + # If the library was installed with an old release of libtool, + # it will not redefine variable installed. + installed=yes + + # Read the .la file + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test $linkmode = oldlib && test $linkmode = obj; }; then + # Add dl[pre]opened files of deplib + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test $pass = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit 1 + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + tmp_libs="$tmp_libs $deplib" + done + elif test $linkmode != prog && test $linkmode != lib; then + $echo "$modename: \`$lib' is not a convenience library" 1>&2 + exit 1 + fi + continue + fi # $pass = conv + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit 1 + fi + + # This library was specified with -dlopen. + if test $pass = dlopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2 + exit 1 + fi + if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. + dlprefiles="$dlprefiles $lib" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2 + $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 + abs_ladir="$ladir" + fi + ;; + esac + laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + $echo "$modename: warning: library \`$lib' was moved." 1>&2 + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi # $installed = yes + name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + + # This library was specified with -dlpreopen. + if test $pass = dlpreopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2 + exit 1 + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test $linkmode = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" + fi + continue + fi + + if test $linkmode = prog && test $pass != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test + esac + # Need to link against all dependency_libs? + if test $linkalldeplibs = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + link_static=no # Whether the deplib will be linked statically + if test -n "$library_names" && + { test "$prefer_static_libs" = no || test -z "$old_library"; }; then + # Link against this shared library + + if test "$linkmode,$pass" = "prog,link" || + { test $linkmode = lib && test $hardcode_into_libs = yes; }; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + if test $linkmode = prog; then + # We need to hardcode the library path + if test -n "$shlibpath_var"; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath " in + *" $dir "*) ;; + *" $absdir "*) ;; + *) temp_rpath="$temp_rpath $dir" ;; + esac + fi + fi + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + realname="$2" + shift; shift + libname=`eval \\$echo \"$libname_spec\"` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin*) + major=`expr $current - $age` + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + soname=`echo $soroot | sed -e 's/^.*\///'` + newlib="libimp-`echo $soname | sed 's/^lib//;s/\.dll$//'`.a" + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + $show "extracting exported symbol list from \`$soname'" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + eval cmds=\"$extract_expsyms_cmds\" + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + $show "generating import library for \`$soname'" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + eval cmds=\"$old_archive_from_expsyms_cmds\" + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n $old_archive_from_expsyms_cmds + + if test $linkmode = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + $echo "$modename: configuration error: unsupported hardcode properties" + exit 1 + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test $linkmode = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && \ + test "$hardcode_minus_L" != yes && \ + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test $linkmode = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + add="-l$name" + fi + + if test $linkmode = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test $linkmode = prog; then + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + + # Try to link the static library + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + echo + echo "*** Warning: This library needs some functionality provided by $lib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + echo "*** Therefore, libtool will create a static module, that should work " + echo "*** as long as the dlopening application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + convenience="$convenience $dir/$old_library" + old_convenience="$old_convenience $dir/$old_library" + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test $linkmode = lib; then + if test -n "$dependency_libs" && + { test $hardcode_into_libs != yes || test $build_old_libs = yes || + test $link_static = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'` + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + tmp_libs="$tmp_libs $deplib" + done + + if test $link_all_deplibs != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + case $deplib in + -L*) path="$deplib" ;; + *.la) + dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$deplib" && dir="." + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 + absdir="$dir" + fi + ;; + esac + if grep "^installed=no" $deplib > /dev/null; then + path="-L$absdir/$objdir" + else + eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit 1 + fi + if test "$absdir" != "$libdir"; then + $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2 + fi + path="-L$absdir" + fi + ;; + *) continue ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$deplibs $path" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test $pass = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test $pass != dlopen; then + test $pass != scan && dependency_libs="$newdependency_libs" + if test $pass != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + *) + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + if test "$pass" = "conv" && + { test "$linkmode" = "lib" || test "$linkmode" = "prog"; }; then + libs="$deplibs" # reset libs + deplibs= + fi + done # for pass + if test $linkmode = prog; then + dlfiles="$newdlfiles" + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for archives" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 + fi + + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 + fi + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + eval libname=\"$libname_spec\" + ;; + *) + if test "$module" = no; then + $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + eval libname=\"$libname_spec\" + else + libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1 + exit 1 + else + echo + echo "*** Warning: Linking the shared library $output against the non-libtool" + echo "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + if test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2 + fi + + set dummy $rpath + if test $# -gt 2; then + $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 + fi + install_libdir="$2" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + libext=al + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for convenience libraries" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 + fi + else + + # Parse the version information argument. + IFS="${IFS= }"; save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + IFS="$save_ifs" + + if test -n "$8"; then + $echo "$modename: too many parameters to \`-version-info'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + current="$2" + revision="$3" + age="$4" + + # Check that each of the things are valid numbers. + case $current in + 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;; + *) + $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case $revision in + 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;; + *) + $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case $age in + 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;; + *) + $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + if test $age -gt $current; then + $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + minor_current=`expr $current + 1` + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current"; + ;; + + irix) + major=`expr $current - $age + 1` + verstring="sgi$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test $loop != 0; do + iface=`expr $revision - $loop` + loop=`expr $loop - 1` + verstring="sgi$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + ;; + + osf) + major=`expr $current - $age` + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test $loop != 0; do + iface=`expr $current - $loop` + loop=`expr $loop - 1` + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + major=`expr $current - $age` + versuffix="-$major" + ;; + + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + verstring="0.0" + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + fi + + if test "$mode" != relink; then + # Remove our outputs. + $show "${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*" + $run ${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.* + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + for path in $notinst_path; do + lib_search_path=`echo "$lib_search_path " | sed -e 's% $path % %g'` + deplibs=`echo "$deplibs " | sed -e 's% -L$path % %g'` + dependency_libs=`echo "$dependency_libs " | sed -e 's% -L$path % %g'` + done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test $hardcode_into_libs != yes || test $build_old_libs = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs -framework System" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test $build_libtool_need_lc = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behaviour. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $rm conftest.c + cat > conftest.c </dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null \ + | grep " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | sed 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ + | sed 10q \ + | egrep "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + echo "*** Warning: This library needs some functionality provided by $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + for a_deplib in $deplibs; do + name="`expr $a_deplib : '-l\(.*\)'`" + # If $name is empty we are operating on a -L argument. + if test -n "$name" && test "$name" != "0"; then + libname=`eval \\$echo \"$libname_spec\"` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + if eval echo \"$potent_lib\" 2>/dev/null \ + | sed 10q \ + | egrep "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + echo "*** Warning: This library needs some functionality provided by $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + if $echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ + -e 's/ -[LR][^ ]*//g' -e 's/[ ]//g' | + grep . >/dev/null; then + echo + if test "X$deplibs_check_method" = "Xnone"; then + echo "*** Warning: inter-library dependencies are not supported in this platform." + else + echo "*** Warning: inter-library dependencies are not known to be supported." + fi + echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + echo + echo "*** Warning: libtool could not satisfy all declared inter-library" + echo "*** dependencies of module $libname. Therefore, libtool will create" + echo "*** a static module, that should work as long as the dlopening" + echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + echo "*** The inter-library dependencies that have been dropped here will be" + echo "*** automatically added whenever a program is linked with this library" + echo "*** or is declared to -dlopen it." + + if test $allow_undefined = no; then + echo + echo "*** Since this library must not contain undefined symbols," + echo "*** because either the platform does not support them or" + echo "*** it was explicitly requested with -no-undefined," + echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test $hardcode_into_libs = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval library_names=\"$library_names_spec\" + set dummy $library_names + realname="$2" + shift; shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + test -z "$dlname" && dlname=$soname + + lib="$output_objdir/$realname" + for link + do + linknames="$linknames $link" + done + + # Ensure that we have .o objects for linkers which dislike .lo + # (e.g. aix) in case we are running --disable-static + for obj in $libobjs; do + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"` + if test ! -f $xdir/$oldobj; then + $show "(cd $xdir && ${LN_S} $baseobj $oldobj)" + $run eval '(cd $xdir && ${LN_S} $baseobj $oldobj)' || exit $? + fi + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + eval cmds=\"$export_symbols_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + if test -n "$export_symbols_regex"; then + $show "egrep -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" + $run eval 'egrep -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + $show "$mv \"${export_symbols}T\" \"$export_symbols\"" + $run eval '$mv "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' + fi + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${outputname}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "mkdir $gentop" + $run mkdir "$gentop" + status=$? + if test $status -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + for xlib in $convenience; do + # Extract the objects. + case $xlib in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "mkdir $xdir" + $run mkdir "$xdir" + status=$? + if test $status -ne 0 && test ! -d "$xdir"; then + exit $status + fi + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + + libobjs="$libobjs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP` + done + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval cmds=\"$archive_expsym_cmds\" + else + eval cmds=\"$archive_cmds\" + fi + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $? + exit 0 + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 + fi + + case $output in + *.lo) + if test -n "$objs$old_deplibs"; then + $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 + exit 1 + fi + libobj="$output" + obj=`$echo "X$output" | $Xsed -e "$lo2o"` + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $run $rm $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${obj}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "mkdir $gentop" + $run mkdir "$gentop" + status=$? + if test $status -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + for xlib in $convenience; do + # Extract the objects. + case $xlib in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "mkdir $xdir" + $run mkdir "$xdir" + status=$? + if test $status -ne 0 && test ! -d "$xdir"; then + exit $status + fi + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + + reload_conv_objs="$reload_objs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP` + done + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + eval cmds=\"$reload_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit 0 + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + $show "echo timestamp > $libobj" + $run eval "echo timestamp > $libobj" || exit $? + exit 0 + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + eval cmds=\"$reload_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + else + # Just create a symlink. + $show $rm $libobj + $run $rm $libobj + xdir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$libobj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$libobj" | $Xsed -e 's%^.*/%%'` + oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"` + $show "(cd $xdir && $LN_S $oldobj $baseobj)" + $run eval '(cd $xdir && $LN_S $oldobj $baseobj)' || exit $? + fi + + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit 0 + ;; + + prog) + case $host in + *cygwin*) output=`echo $output | sed -e 's,.exe$,,;s,$,.exe,'` ;; + esac + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 + fi + + if test "$preload" = yes; then + if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown && + test "$dlopen_self_static" = unknown; then + $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." + fi + fi + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + case :$dllsearchpath: in + *":$libdir:"*) ;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + dlsyms= + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + dlsyms="${outputname}S.c" + else + $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 + fi + fi + + if test -n "$dlsyms"; then + case $dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${outputname}.nm" + + $show "$rm $nlist ${nlist}S ${nlist}T" + $run $rm "$nlist" "${nlist}S" "${nlist}T" + + # Parse the name list into a source file. + $show "creating $output_objdir/$dlsyms" + + test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ +/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ +/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* Prevent the only kind of declaration conflicts we can make. */ +#define lt_preloaded_symbols some_other_symbol + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + $show "generating symbol list for \`$output'" + + test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for arg in $progfiles; do + $show "extracting global C symbols from \`$arg'" + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $run eval 'egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + if test -n "$export_symbols_regex"; then + $run eval 'egrep -e "$export_symbols_regex" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$output.exp" + $run $rm $export_symbols + $run eval "sed -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + else + $run eval "sed -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"' + $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T' + $run eval 'mv "$nlist"T "$nlist"' + fi + fi + + for arg in $dlprefiles; do + $show "extracting global C symbols from \`$arg'" + name=`echo "$arg" | sed -e 's%^.*/%%'` + $run eval 'echo ": $name " >> "$nlist"' + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -z "$run"; then + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $mv "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if grep -v "^: " < "$nlist" | sort +2 | uniq > "$nlist"S; then + : + else + grep -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' + else + echo '/* NONE */' >> "$output_objdir/$dlsyms" + fi + + $echo >> "$output_objdir/$dlsyms" "\ + +#undef lt_preloaded_symbols + +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[] = +{\ +" + + sed -n -e 's/^: \([^ ]*\) $/ {\"\1\", (lt_ptr_t) 0},/p' \ + -e 's/^. \([^ ]*\) \([^ ]*\)$/ {"\2", (lt_ptr_t) \&\2},/p' \ + < "$nlist" >> "$output_objdir/$dlsyms" + + $echo >> "$output_objdir/$dlsyms" "\ + {0, (lt_ptr_t) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + fi + + pic_flag_for_symtable= + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DPIC -DFREEBSD_WORKAROUND";; + esac;; + *-*-hpux*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DPIC";; + esac + esac + + # Now compile the dynamic symbol file. + $show "(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" + $run eval '(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? + + # Clean up the generated files. + $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" + $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" + + # Transform the symbol file into the correct name. + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + ;; + *) + $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 + exit 1 + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi + + if test $need_relink = no || test "$build_libtool_libs" != yes; then + # Replace the output file specification. + compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + $show "$link_command" + $run eval "$link_command" + status=$? + + # Delete the generated files. + if test -n "$dlsyms"; then + $show "$rm $output_objdir/${outputname}S.${objext}" + $run $rm "$output_objdir/${outputname}S.${objext}" + fi + + exit $status + fi + + if test -n "$shlibpath_var"; then + # We should set the shlibpath_var + rpath= + for dir in $temp_rpath; do + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) + # Absolute path. + rpath="$rpath$dir:" + ;; + *) + # Relative path: add a thisdir entry. + rpath="$rpath\$thisdir/$dir:" + ;; + esac + done + temp_rpath="$rpath" + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $run $rm $output + # Link the executable and exit + $show "$link_command" + $run eval "$link_command" || exit $? + exit 0 + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 + $echo "$modename: \`$output' will be relinked during installation" 1>&2 + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname + + $show "$link_command" + $run eval "$link_command" || exit $? + + # Now create the wrapper script. + $show "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + relink_command="cd `pwd`; $relink_command" + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + fi + + # Quote $echo for shipping. + if test "X$echo" = "X$SHELL $0 --fallback-echo"; then + case $0 in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $0 --fallback-echo";; + *) qecho="$SHELL `pwd`/$0 --fallback-echo";; + esac + qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if our run command is non-null. + if test -z "$run"; then + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) output=`echo $output|sed 's,.exe$,,'` ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) exeext=.exe ;; + *) exeext= ;; + esac + $rm $output + trap "$rm $output; exit 1" 1 2 15 + + $echo > $output "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variable: + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$echo are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + echo=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$echo works! + : + else + # Restart under the correct shell, and then maybe \$echo will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $echo >> $output "\ + + # Find the directory that this script lives in. + thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | sed -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | sed -n 's/.*-> //p'\` + done + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + echo >> $output "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || \\ + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | sed 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $mkdir \"\$progdir\" + else + $rm \"\$progdir/\$file\" + fi" + + echo >> $output "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if (eval \$relink_command); then : + else + $rm \"\$progdir/\$file\" + exit 1 + fi + fi + + $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $rm \"\$progdir/\$program\"; + $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $rm \"\$progdir/\$file\" + fi" + else + echo >> $output "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + echo >> $output "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $echo >> $output "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $echo >> $output "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $echo >> $output "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # win32 systems need to use the prog path for dll + # lookup to work + *-*-cygwin* | *-*-pw32*) + $echo >> $output "\ + exec \$progdir/\$program \${1+\"\$@\"} +" + ;; + + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2*) + $echo >> $output "\ + exec \$progdir\\\\\$program \${1+\"\$@\"} +" + ;; + + *) + $echo >> $output "\ + # Export the path to the program. + PATH=\"\$progdir:\$PATH\" + export PATH + + exec \$program \${1+\"\$@\"} +" + ;; + esac + $echo >> $output "\ + \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" + exit 1 + fi + else + # The program doesn't exist. + \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2 + \$echo \"This script is just a wrapper for \$program.\" 1>&2 + echo \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" + chmod +x $output + fi + exit 0 + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$objs$old_deplibs "`$echo "X$libobjs_save" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP` + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "mkdir $gentop" + $run mkdir "$gentop" + status=$? + if test $status -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + # Add in members from convenience archives. + for xlib in $addlibs; do + # Extract the objects. + case $xlib in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "mkdir $xdir" + $run mkdir "$xdir" + status=$? + if test $status -ne 0 && test ! -d "$xdir"; then + exit $status + fi + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + + oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP` + done + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + eval cmds=\"$old_archive_from_new_cmds\" + else + # Ensure that we have .o objects in place in case we decided + # not to build a shared library, and have fallen back to building + # static libs even though --disable-static was passed! + for oldobj in $oldobjs; do + if test ! -f $oldobj; then + xdir=`$echo "X$oldobj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$oldobj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$oldobj" | $Xsed -e 's%^.*/%%'` + obj=`$echo "X$baseobj" | $Xsed -e "$o2lo"` + $show "(cd $xdir && ${LN_S} $obj $baseobj)" + $run eval '(cd $xdir && ${LN_S} $obj $baseobj)' || exit $? + fi + done + + eval cmds=\"$old_archive_cmds\" + fi + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$generated"; then + $show "${rm}r$generated" + $run ${rm}r$generated + fi + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + $show "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="cd `pwd`; $SHELL $0 --mode=relink $libtool_args" + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + + # Only create the output if not a dry run. + if test -z "$run"; then + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'` + eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit 1 + fi + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + for lib in $dlfiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit 1 + fi + newdlfiles="$newdlfiles $libdir/$name" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit 1 + fi + newdlprefiles="$newdlprefiles $libdir/$name" + done + dlprefiles="$newdlprefiles" + fi + $rm $output + # place dlname in correct position for cygwin + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + esac + $echo > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test $need_relink = yes; then + $echo >> $output "\ +relink_command=\"$relink_command\"" + fi + done + fi + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" + $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $? + ;; + esac + exit 0 + ;; + + # libtool install mode + install) + modename="$modename: install" + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + $echo "X$nonopt" | $Xsed | grep shtool > /dev/null; then + # Aesthetically quote it. + arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$arg " + arg="$1" + shift + else + install_prog= + arg="$nonopt" + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog$arg" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest="$arg" + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) prev="-f" ;; + -g) prev="-g" ;; + -m) prev="-m" ;; + -o) prev="-o" ;; + -s) + stripme=" -s" + continue + ;; + -*) ;; + + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest="$arg" + continue + fi + ;; + esac + + # Aesthetically quote the argument. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog $arg" + done + + if test -z "$install_prog"; then + $echo "$modename: you must specify an install program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -n "$prev"; then + $echo "$modename: the \`$prev' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -z "$files"; then + if test -z "$dest"; then + $echo "$modename: no file or destination specified" 1>&2 + else + $echo "$modename: you must specify a destination" 1>&2 + fi + $echo "$help" 1>&2 + exit 1 + fi + + # Strip any trailing slash from the destination. + dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` + test "X$destdir" = "X$dest" && destdir=. + destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` + + # Not a directory, so check to see that there is only one file specified. + set dummy $files + if test $# -gt 2; then + $echo "$modename: \`$dest' is not a directory" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + library_names= + old_library= + relink_command= + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/ + test "X$dir" = "X$file/" && dir= + dir="$dir$objdir" + + if test -n "$relink_command"; then + $echo "$modename: warning: relinking \`$file'" 1>&2 + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + continue + fi + fi + + # See the names of the shared library. + set dummy $library_names + if test -n "$2"; then + realname="$2" + shift + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + $show "$install_prog $dir/$srcname $destdir/$realname" + $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $? + if test -n "$stripme" && test -n "$striplib"; then + $show "$striplib $destdir/$realname" + $run eval "$striplib $destdir/$realname" || exit $? + fi + + if test $# -gt 0; then + # Delete the old symlinks, and create new ones. + for linkname + do + if test "$linkname" != "$realname"; then + $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" + fi + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + eval cmds=\"$postinstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Install the pseudo-library for information purposes. + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + instname="$dir/$name"i + $show "$install_prog $instname $destdir/$name" + $run eval "$install_prog $instname $destdir/$name" || exit $? + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + + # Install the libtool object if requested. + if test -n "$destfile"; then + $show "$install_prog $file $destfile" + $run eval "$install_prog $file $destfile" || exit $? + fi + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` + + $show "$install_prog $staticobj $staticdest" + $run eval "$install_prog \$staticobj \$staticdest" || exit $? + fi + exit 0 + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Do a test to see if this is really a libtool program. + if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + notinst_deplibs= + relink_command= + + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Check the variables that should have been set. + if test -z "$notinst_deplibs"; then + $echo "$modename: invalid libtool wrapper script \`$file'" 1>&2 + exit 1 + fi + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + # If there is no directory component, then add one. + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + fi + libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 + finalize=no + fi + done + + relink_command= + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + if test "$finalize" = yes && test -z "$run"; then + tmpdir="/tmp" + test -n "$TMPDIR" && tmpdir="$TMPDIR" + tmpdir="$tmpdir/libtool-$$" + if $mkdir -p "$tmpdir" && chmod 700 "$tmpdir"; then : + else + $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2 + continue + fi + file=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` + + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + ${rm}r "$tmpdir" + continue + fi + file="$outputname" + else + $echo "$modename: warning: cannot relink \`$file'" 1>&2 + fi + else + # Install the binary that we compiled earlier. + file=`$echo "X$file" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyways + case $install_prog,$host in + /usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + destfile=`echo $destfile | sed -e 's,.exe$,,'` + ;; + esac + ;; + esac + $show "$install_prog$stripme $file $destfile" + $run eval "$install_prog\$stripme \$file \$destfile" || exit $? + test -n "$outputname" && ${rm}r "$tmpdir" + ;; + esac + done + + for file in $staticlibs; do + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + $show "$install_prog $file $oldlib" + $run eval "$install_prog \$file \$oldlib" || exit $? + + if test -n "$stripme" && test -n "$striplib"; then + $show "$old_striplib $oldlib" + $run eval "$old_striplib $oldlib" || exit $? + fi + + # Do each command in the postinstall commands. + eval cmds=\"$old_postinstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$future_libdirs"; then + $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 + fi + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + test -n "$run" && current_libdirs=" -n$current_libdirs" + exec $SHELL $0 --finish$current_libdirs + exit 1 + fi + + exit 0 + ;; + + # libtool finish mode + finish) + modename="$modename: finish" + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + eval cmds=\"$finish_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || admincmds="$admincmds + $cmd" + done + IFS="$save_ifs" + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $run eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + test "$show" = ":" && exit 0 + + echo "----------------------------------------------------------------------" + echo "Libraries have been installed in:" + for libdir in $libdirs; do + echo " $libdir" + done + echo + echo "If you ever happen to want to link against installed libraries" + echo "in a given directory, LIBDIR, you must either use libtool, and" + echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + echo " during execution" + fi + if test -n "$runpath_var"; then + echo " - add LIBDIR to the \`$runpath_var' environment variable" + echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + echo " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + echo " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + echo + echo "See any operating system documentation about shared libraries for" + echo "more information, such as the ld(1) and ld.so(8) manual pages." + echo "----------------------------------------------------------------------" + exit 0 + ;; + + # libtool execute mode + execute) + modename="$modename: execute" + + # The first argument is the command name. + cmd="$nonopt" + if test -z "$cmd"; then + $echo "$modename: you must specify a COMMAND" 1>&2 + $echo "$help" + exit 1 + fi + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + if test ! -f "$file"; then + $echo "$modename: \`$file' is not a file" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Read the libtool library. + dlname= + library_names= + + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" + continue + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 + exit 1 + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + ;; + + *) + $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` + args="$args \"$file\"" + done + + if test -z "$run"; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved enviroment variables + if test "${save_LC_ALL+set}" = set; then + LC_ALL="$save_LC_ALL"; export LC_ALL + fi + if test "${save_LANG+set}" = set; then + LANG="$save_LANG"; export LANG + fi + + # Now actually exec the command. + eval "exec \$cmd$args" + + $echo "$modename: cannot exec \$cmd$args" + exit 1 + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" + $echo "export $shlibpath_var" + fi + $echo "$cmd$args" + exit 0 + fi + ;; + + # libtool clean and uninstall mode + clean | uninstall) + modename="$modename: $mode" + rm="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) rm="$rm $arg"; rmforce=yes ;; + -*) rm="$rm $arg" ;; + *) files="$files $arg" ;; + esac + done + + if test -z "$rm"; then + $echo "$modename: you must specify an RM program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + rmdirs= + + for file in $files; do + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$file"; then + dir=. + objdir="$objdir" + else + objdir="$dir/$objdir" + fi + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + test $mode = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test $mode = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if (test -L "$file") >/dev/null 2>&1 \ + || (test -h "$file") >/dev/null 2>&1 \ + || test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + . $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + test $mode = clean && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + + if test $mode = uninstall; then + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + eval cmds=\"$postuninstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" + if test $? != 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + eval cmds=\"$old_postuninstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" + if test $? != 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + # FIXME: should reinstall the best remaining shared library. + fi + fi + ;; + + *.lo) + if test "$build_old_libs" = yes; then + oldobj=`$echo "X$name" | $Xsed -e "$lo2o"` + rmfiles="$rmfiles $dir/$oldobj" + fi + ;; + + *) + # Do a test to see if this is a libtool program. + if test $mode = clean && + (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + relink_command= + . $dir/$file + + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + fi + ;; + esac + $show "$rm $rmfiles" + $run $rm $rmfiles || exit_status=1 + done + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + $show "rmdir $dir" + $run rmdir $dir >/dev/null 2>&1 + fi + done + + exit $exit_status + ;; + + "") + $echo "$modename: you must specify a MODE" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 + ;; + esac + + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 +fi # test -z "$show_help" + +# We need to display help for each of the modes. +case $mode in +"") $echo \ +"Usage: $modename [OPTION]... [MODE-ARG]... + +Provide generalized library-building support services. + + --config show all configuration variables + --debug enable verbose shell tracing +-n, --dry-run display commands without modifying any files + --features display basic configuration information and exit + --finish same as \`--mode=finish' + --help display this help message and exit + --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] + --quiet same as \`--silent' + --silent don't print informational messages + --version print version information + +MODE must be one of the following: + + clean remove files from the build directory + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for +a more detailed description of MODE." + exit 0 + ;; + +clean) + $echo \ +"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + +compile) + $echo \ +"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -static always build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + +execute) + $echo \ +"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + +finish) + $echo \ +"Usage: $modename [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + +install) + $echo \ +"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + +link) + $echo \ +"Usage: $modename [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -static do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + +uninstall) + $echo \ +"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + +*) + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; +esac + +echo +$echo "Try \`$modename --help' for more information about other modes." + +exit 0 + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/contrib/bind-9.2.4rc7/lib/bind/make/includes.in b/contrib/bind-9.2.4rc7/lib/bind/make/includes.in new file mode 100644 index 0000000000..b8265d56f8 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/make/includes.in @@ -0,0 +1,44 @@ +# Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2001 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: includes.in,v 1.1.2.1 2004/03/15 04:44:47 marka 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.2.4rc7/lib/bind/make/mkdep.in b/contrib/bind-9.2.4rc7/lib/bind/make/mkdep.in new file mode 100644 index 0000000000..60aea6fc6c --- /dev/null +++ b/contrib/bind-9.2.4rc7/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.2.4rc7/lib/bind/make/rules.in b/contrib/bind-9.2.4rc7/lib/bind/make/rules.in new file mode 100644 index 0000000000..592c66ccb4 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/make/rules.in @@ -0,0 +1,177 @@ +# Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2001 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: rules.in,v 1.3.2.6 2004/03/15 04:44:47 marka 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.2.4rc7/lib/bind/mkinstalldirs b/contrib/bind-9.2.4rc7/lib/bind/mkinstalldirs new file mode 100644 index 0000000000..74a611ae83 --- /dev/null +++ b/contrib/bind-9.2.4rc7/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.2.4rc7/lib/bind/nameser/ns_date.c b/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_date.c new file mode 100644 index 0000000000..9ecf5ac4e9 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_date.c @@ -0,0 +1,128 @@ +/* + * 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.3.2.2 2004/03/16 12:35:32 marka 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_name.c b/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_name.c new file mode 100644 index 0000000000..27b031bd32 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_name.c @@ -0,0 +1,963 @@ +/* + * 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.3.2.6 2004/05/04 03:26:16 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 + +#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. */ + +/* + * ns_name_ntop(src, dst, dstsiz) + * Convert an encoded domain name to printable ascii as per RFC1035. + * return: + * Number of bytes written to buffer, or -1 (with errno set) + * notes: + * The root is returned as "." + * 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); +} + +/* + * ns_name_pton(src, dst, dstsiz) + * Convert a ascii string into an encoded domain name as per RFC1035. + * return: + * -1 if it fails + * 1 if string was fully qualified + * 0 is string was not fully qualified + * notes: + * 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); +} + +/* + * ns_name_ntol(src, dst, dstsiz) + * Convert a network strings labels into all lowercase. + * return: + * Number of bytes written to buffer, or -1 (with errno set) + * notes: + * 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); +} + +/* + * ns_name_unpack(msg, eom, src, dst, dstsiz) + * Unpack a domain name from a message, source may be compressed. + * return: + * -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); +} + +/* + * ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr) + * Pack domain name 'domain' into 'comp_dn'. + * return: + * Size of the compressed name, or -1. + * notes: + * 'dnptrs' is an array of pointers to previous compressed names. + * dnptrs[0] is a pointer to the beginning of the message. The array + * ends with NULL. + * 'lastdnptr' is a pointer to the end of the array pointed to + * by 'dnptrs'. + * Side effects: + * 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); +} + +/* + * ns_name_uncompress(msg, eom, src, dst, dstsiz) + * Expand compressed domain name to presentation format. + * return: + * Number of bytes read out of `src', or -1 (with errno set). + * note: + * 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); +} + +/* + * ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr) + * Compress a domain name into wire format, using compression pointers. + * return: + * Number of bytes consumed in `dst' or -1 (with errno set). + * notes: + * 'dnptrs' is an array of pointers to previous compressed names. + * dnptrs[0] is a pointer to the beginning of the message. + * 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. + * 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++; + } +} + +/* + * ns_name_skip(ptrptr, eom) + * Advance *ptrptr to skip over the compressed name it points at. + * return: + * 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. */ + +/* + * special(ch) + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this characted special ("in need of quoting") ? + * return: + * 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); + } +} + +/* + * printable(ch) + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this character visible and not a space when printed ? + * return: + * 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); +} + +/* + * dn_find(domain, msg, dnptrs, lastdnptr) + * Search for the counted-label name in an array of compressed names. + * return: + * offset from msg if found, or -1. + * notes: + * dnptrs is the pointer to the first name on the list, + * 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. + * RFC 2673, 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_netint.c b/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_netint.c new file mode 100644 index 0000000000..9441f42f84 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_netint.c @@ -0,0 +1,56 @@ +/* + * 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.1.2.1 2004/03/09 09:17:37 marka 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_parse.c b/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_parse.c new file mode 100644 index 0000000000..e438e81d84 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_parse.c @@ -0,0 +1,203 @@ +/* + * 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.3.2.2 2004/03/09 09:17:37 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. */ + +#define RETERR(err) do { errno = (err); return (-1); } while (0) + +/* 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. */ + if ((tmp = section) < 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]; + } +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_print.c b/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_print.c new file mode 100644 index 0000000000..2af84b8dac --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_print.c @@ -0,0 +1,898 @@ +/* + * 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.3.2.6 2004/07/28 20:06:58 marka 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. */ + +/* + * int + * ns_sprintrr(handle, rr, name_ctx, origin, buf, buflen) + * Convert an RR to presentation format. + * return: + * 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); +} + +/* + * int + * ns_sprintrrf(msg, msglen, name, class, type, ttl, rdata, rdlen, + * name_ctx, origin, buf, buflen) + * Convert the fields of an RR into presentation format. + * return: + * 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", edata - rdata, + rdlen != 0 ? " (" : "", 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_samedomain.c b/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_samedomain.c new file mode 100644 index 0000000000..fc4b9d9751 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_samedomain.c @@ -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. + */ + +#ifndef lint +static const char rcsid[] = "$Id: ns_samedomain.c,v 1.1.2.4 2004/03/16 12:35:33 marka Exp $"; +#endif + +#include "port_before.h" + +#include +#include +#include +#include + +#include "port_after.h" + +/* + * int + * ns_samedomain(a, b) + * Check whether a name belongs to a domain. + * Inputs: + * a - the domain whose ancestory is being verified + * b - the potential ancestor we're checking against + * Return: + * boolean - is a at or below b? + * Notes: + * 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. + * + * "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); +} + +/* + * int + * ns_subdomain(a, b) + * 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)); +} + +/* + * int + * ns_makecanon(src, dst, dstsize) + * make a canonical copy of domain name "src" + * notes: + * foo -> foo. + * foo. -> foo. + * foo.. -> foo. + * foo\. -> foo\.. + * foo\\. -> foo\\. + */ + +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); +} + +/* + * int + * ns_samename(a, b) + * determine whether domain name "a" is the same as domain name "b" + * return: + * -1 on error + * 0 if names differ + * 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_sign.c b/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_sign.c new file mode 100644 index 0000000000..8a13b80639 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_sign.c @@ -0,0 +1,380 @@ +/* + * 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.1.2.3 2004/03/09 09:17:37 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: + * msg message to be sent + * msglen input - length of message + * output - length of signed message + * msgsize length of buffer containing message + * error value to put in the error field + * key tsig key used for signing + * querysig (response), the signature in the query + * querysiglen (response), the length of the signature in the query + * sig a buffer to hold the generated signature + * siglen input - length of signature buffer + * output - length of signature + * + * Errors: + * - bad input data (-1) + * - bad key / sign failed (-BADKEY) + * - 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 = msg + *msglen, *eob = msg + msgsize; + 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); + + /* 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_ttl.c b/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_ttl.c new file mode 100644 index 0000000000..0e96cf016d --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_ttl.c @@ -0,0 +1,159 @@ +/* + * 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.1.2.1 2004/03/09 09:17:37 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; + } + *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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_verify.c b/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_verify.c new file mode 100644 index 0000000000..7d3ad66a2a --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/nameser/ns_verify.c @@ -0,0 +1,480 @@ +/* + * 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.1.2.1 2004/03/09 09:17:37 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: + * statp res stuff + * msg received message + * msglen length of message + * key tsig key used for verifying. + * querysig (response), the signature in the query + * querysiglen (response), the length of the signature in the query + * sig (query), a buffer to hold the signature + * siglen (query), input - length of signature buffer + * output - length of signature + * + * Errors: + * - bad input (-1) + * - invalid dns message (NS_TSIG_ERROR_FORMERR) + * - TSIG is not present (NS_TSIG_ERROR_NO_TSIG) + * - key doesn't match (-ns_r_badkey) + * - TSIG verification fails with BADKEY (-ns_r_badkey) + * - TSIG verification fails with BADSIG (-ns_r_badsig) + * - TSIG verification fails with BADTIME (-ns_r_badtime) + * - TSIG verification succeeds, error set to BAKEY (ns_r_badkey) + * - TSIG verification succeeds, error set to BADSIG (ns_r_badsig) + * - 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, id, 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; + + /* Read the original id and error. */ + BOUNDS_CHECK(cp, 2*INT16SZ); + GETSHORT(id, cp); + 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, *rdatastart, *sigstart; + unsigned int sigfieldlen, otherfieldlen; + u_char *cp, *eom = msg + *msglen, *cp2; + char name[MAXDNAME], alg[MAXDNAME]; + u_char buf[MAXDNAME]; + int n, type, length, fudge, id, error; + time_t timesigned; + + if (msg == NULL || msglen == NULL || state == NULL) + return (-1); + + 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. */ + 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; + + /* 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; + + /* Read the original id and error. */ + BOUNDS_CHECK(cp, 2*INT16SZ); + GETSHORT(id, cp); + 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); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/port/freebsd/include/sys/bitypes.h b/contrib/bind-9.2.4rc7/lib/bind/port/freebsd/include/sys/bitypes.h new file mode 100644 index 0000000000..ef3a6d4832 --- /dev/null +++ b/contrib/bind-9.2.4rc7/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.2.4rc7/lib/bind/port_after.h.in b/contrib/bind-9.2.4rc7/lib/bind/port_after.h.in new file mode 100644 index 0000000000..6d5f4dca66 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/port_after.h.in @@ -0,0 +1,395 @@ +#ifndef port_after_h +#define port_after_h + +#include +#include +#include +#include +#if (!defined(BSD)) || (BSD < 199306) +#include +#endif + +@NEED_PSELECT@ +@HAVE_SA_LEN@ +@HAVE_MINIMUM_IFREQ@ +@NEED_DAEMON@ +@NEED_STRSEP@ +@NEED_STRERROR@ +@HAS_INET6_STRUCTS@ +@HAVE_SIN6_SCOPE_ID@ +@NEED_IN6ADDR_ANY@ +@HAS_IN_ADDR6@ +@HAVE_SOCKADDR_STORAGE@ +@NEED_GETTIMEOFDAY@ +@HAVE_STRNDUP@ +@USE_FIONBIO_IOCTL@ +@USE_SYSERROR_LIST@ +@INNETGR_ARGS@ +@SETNETGRENT_ARGS@ +@USE_IFNAMELINKID@ + +/* XXX sunos and cygwin needs O_NDELAY */ +#define PORT_NONBLOCK O_NONBLOCK + +/* + * 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 + +#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) (((unsigned int)(p) + (sizeof(int) - 1)) & ~(sizeof(int) - 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 + +#ifdef NEED_INNETGR_R +NGR_R_RETURN +innetgr_r(const char *, const char *, const char *, const char *); +#endif + +#ifdef NEED_SETNETGRENT_R +#ifdef NGR_R_ENT_ARGS +NGR_R_SET_RETURN setnetgrent_r(const char *netgroup, NGR_R_ENT_ARGS); +#else +NGR_R_SET_RETURN setnetgrent_r(const char *netgroup); +#endif +#endif + +#ifdef NEED_ENDNETGRENT_R +#ifdef NGR_R_ENT_ARGS +NGR_R_END_RETURN endnetgrent_r(NGR_R_ENT_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(char **machinep, char **userp, char **domainp); + +int getnetgrent_r(char **machinep, char **userp, char **domainp, NGR_R_ARGS); + +#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_ENT_ARGS +NGR_R_SET_RETURN +setnetgrent_r(const char *netgroup, NGR_R_ENT_ARGS); +#else +NGR_R_SET_RETURN +setnetgrent_r(const char *netgroup); +#endif +#endif diff --git a/contrib/bind-9.2.4rc7/lib/bind/port_before.h.in b/contrib/bind-9.2.4rc7/lib/bind/port_before.h.in new file mode 100644 index 0000000000..d6fbe86ac1 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/port_before.h.in @@ -0,0 +1,138 @@ +#ifndef port_before_h +#define port_before_h +#include + +struct group; /* silence warning */ +struct passwd; /* silence warning */ +struct timeval; /* silence warning */ +struct timezone; /* silence warning */ + +#ifdef HAVE_SYS_TIMERS_H +#include +#endif +#include + + +@WANT_IRS_GR@ +@WANT_IRS_NIS@ +@WANT_IRS_PW@ + +@BSD_COMP@ + +@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_END_RESULT@ +@NGR_R_END_RETURN@ +@NGR_R_ENT_ARGS@ +@NGR_R_OK@ +@NGR_R_RETURN@ +@NGR_R_SET_RESULT@ +@NGR_R_SET_RETURN@ +@NGR_R_PRIVATE@ + +@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_OK@ +@PROTO_R_SETANSWER@ +@PROTO_R_RETURN@ +@PROTO_R_SET_RESULT@ +@PROTO_R_SET_RETURN@ + +@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_OK@ +@SERV_R_SETANSWER@ +@SERV_R_RETURN@ +@SERV_R_SET_RESULT@ +@SERV_R_SET_RETURN@ + + +#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 + +#endif diff --git a/contrib/bind-9.2.4rc7/lib/bind/resolv/herror.c b/contrib/bind-9.2.4rc7/lib/bind/resolv/herror.c new file mode 100644 index 0000000000..cacba8b4b2 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/resolv/herror.c @@ -0,0 +1,127 @@ +/* + * 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.2.2.1 2004/03/09 09:17:48 marka 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"); +} diff --git a/contrib/bind-9.2.4rc7/lib/bind/resolv/res_comp.c b/contrib/bind-9.2.4rc7/lib/bind/resolv/res_comp.c new file mode 100644 index 0000000000..1c26c6c5a3 --- /dev/null +++ b/contrib/bind-9.2.4rc7/lib/bind/resolv/res_comp.c @@ -0,0 +1,251 @@ +/* + * 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.1.2.2 2004/03/09 09:17:49 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. + * 'msg' is a pointer to the begining of the message, + * 'eom' points to the first location after the message, + * 'dst' is a pointer to a buffer of size 'dstsiz' for the result. + * 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'. + * Return the size of the compressed name or -1. + * '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